1. 程式人生 > 實用技巧 >程式語言在函式中的引數傳遞

程式語言在函式中的引數傳遞

1、Python

Python 的引數傳遞是賦值傳遞 (pass by assignment),或者叫作物件的引用傳遞(pass by object reference)。Python 裡所有的資料型別都是物件,所以引數傳遞時,只是讓新變數與原變數指向相同的物件而已,並不存在值傳遞或是引用傳遞一說。 ----來自網際網路

總結一下:就是在使用函式時,把實參賦給函式的形參,即形參=實參,函式的形參和實參指向同一物件。

那麼在函式中引數的變化只受其本身物件的性質影響了。

Python中的資料型別有可變不可變,string

這種不可變型別被修改後相當於重新賦值,控制代碼指向新的物件。

傳遞string(不可變)

def fun(a:str):
    print("2  ",id(a))
    a+="b"
    print("3   ",id(a))


a="aa"
print(id(a))

fun(a)

print(a)

1753958904624 
2   1753958904624    #傳遞前後是一個物件
3    1753960317104   #string是不可變型別,修改了就是另一個物件
aa 

傳遞list(可變型別)

def fun(a:list):
    print("2  ",id(a))
    a.append("1")
    print("3   ",id(a))


a=['a','b']
print(id(a))

fun(a)

print(a)

2017284788416         #傳遞前後是一個物件
2   2017284788416
3    2017284788416   #list是可變型別,即使修改了,物件也沒變
['a', 'b', '1']      

2、JS

JS和Python一樣,也是直接把實參給了形參。

string(不可變的值型別)

function f(str) {
    console.log("內部:  ",str==="Hello World");
    str += "!";
    return str;
}

var str="Hello World";
console.log("外部1: ",str==="Hello World");

console.log("外部2:   ",str===f(str));


外部1:  true
內部:   true
外部2:    false

Array(引用型別)

function f(arr2) {
   console.log(arr===arr2);
   arr2.push("!");
   console.log(arr===arr2);
}

var arr=[];
arr.push("hello");
arr.push("world");

f(arr);

console.log("陣列: ",arr);

true
true
陣列:  [ 'hello', 'world', '!' ]

3、Java

Java的資料型別分為兩種:基本型別和引用型別。

引用型別分為下面幾種:類型別(class,interface,enum,annotation)和陣列型別 。

Java也是賦值傳遞。

int(基本型別)

基本型別不需要new,賦值直接使用,修改了控制代碼就指向新的位置了。

public class Args_ref {


    public static int f(int x){
        x+=1;
        return x;
    }


    
    public static void main(String[] args) {
        int x=10;
        int y=f(x);
        System.out.printf("x=%d, y=%d, x==y?%b",x,y,x==y);

    }
    
}
x=10, y=11, x==y?false

陣列(物件)

陣列是物件。

 	public static int[] ff(int[] x){
        System.out.println("ff hashCode: "+x.hashCode());
        if(x!=null){
            x[0]=100;    //修改一下x中的元素,也就是對原陣列進行修改
        }
        return x;
    }

	public static void main(String[] args) {

        int[] s={1,2,3,4};
    
        System.out.println("main hashCode: "+s.hashCode());

        System.out.println("main ff hashCode: "+ff(s).hashCode());

        for(int i:s){
            System.out.println(i);
        }
}
main hashCode: 366712642  //陣列傳遞前後,修改前後都沒有變化
ff hashCode: 366712642  
main ff hashCode: 366712642 
100                
2
3
4

String(物件、不可變)

JavaString是物件型別,但也是不可變的,修改也是重新賦值,控制代碼指向新的字面量。

public static String ss(String s){
        System.out.println("ss1: "+s.hashCode());
        s+="nice";
        System.out.println("ss2: "+s.hashCode());
        return s;

    }


    public static void main(String[] args) {

        String s="Hello Java";

        System.out.println("main1: "+s.hashCode());

        
        System.out.println("main2: "+ss(s).hashCode());
        System.out.println(s);

    }
main1: 387417328   //傳遞前後沒有變化
ss1: 387417328
ss2: 85926989       //修改後hashCode不一樣了
main2: 85926989
Hello Java

4、GO

Go語言和C一樣,是傳值的,就是把實參拷貝一份給形參,不管你是值型別還是引用型別。

Go語言不同於Python\Java,因為它提供了指標,可以通過傳遞指標,達到上面那些語言的功能。

Go中就通過指標模擬面向物件的this關鍵字

String(值型別)

Go中的String是值型別,

//值型別是拷貝
func f(data string){
	fmt.Printf("data:  %p\n",&data)
	data+="hi"
}

func main()  {
	var s string="ok"
	fmt.Printf("s    :  %p\n",&s)
	f(s)

	fmt.Println("s    :  "+s)
}


s    :  0xc0000421f0  
data:  0xc000042200  //地址不一樣,拷貝了一份新的
s    :  ok          

[]string切片

func a(data []string)  {

	fmt.Printf("data1:  %p\n",&data)
	adata:=append(data,"!")      //生成了新切片,從append函式也可以看出是拷貝了,否則沒必要返回一個新切片
    							//func append(slice []Type, elems ...Type) []Type
	fmt.Printf("data2:  %p,%s\n",&data,data)
	fmt.Printf("adata:  %p,%s\n",&adata,adata)

}

func main()  {
	var scl []string=[]string{"Hi ","My ","Friend "}
	fmt.Printf("scl:  %p\n",&scl)
	a(scl)  //把實參拷貝一份給形參,互不影響

	fmt.Println(scl) 

}

scl:  0xc000004480
data1:  0xc0000044c0     //拷貝到新的記憶體裡      
data2:  0xc0000044c0,[Hi  My  Friend ]
adata:  0xc0000044e0,[Hi  My  Friend  !] 
[Hi  My  Friend ]    

[]string(切片指標)

把地址作值傳進去,這時形參修改也會影響到實參了。

Go中模擬面向物件時,用這個特性模擬this關鍵字。

func a(data *[]string)  { 

	fmt.Printf("data1:  %p\n",data)
	if len(*data)>=0{
		(*data)[0]="nono"   //這裡修改就會影響到外界
	}

}

func main()  {
	var scl *[]string=&[]string{"Hi ","My ","Friend "}
	fmt.Printf("scl:  %p\n",scl)
	a(scl)

	fmt.Println(scl)

}


scl:  0xc000068440     //地址相同
data1:  0xc000068440
&[nono My  Friend ]    //函式影響到了外界