程式語言在函式中的引數傳遞
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(物件、不可變)
Java
中String
是物件型別,但也是不可變的,修改也是重新賦值,控制代碼指向新的字面量。
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 ] //函式影響到了外界