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语言不同于PythonJava,因为它提供了指针,可以通过传递指针,达到上面那些语言的功能。
Go中就通过指针模拟面向对象的this关键字
String(值类型)
Go
中的String
是值类型,
//值类型是拷贝
func f(data string){
fmt.Printf("data: %p
",&data)
data+="hi"
}
func main() {
var s string="ok"
fmt.Printf("s : %p
",&s)
f(s)
fmt.Println("s : "+s)
}
s : 0xc0000421f0
data: 0xc000042200 //地址不一样,拷贝了一份新的
s : ok
[]string切片
func a(data []string) {
fmt.Printf("data1: %p
",&data)
adata:=append(data,"!") //生成了新切片,从append函数也可以看出是拷贝了,否则没必要返回一个新切片
//func append(slice []Type, elems ...Type) []Type
fmt.Printf("data2: %p,%s
",&data,data)
fmt.Printf("adata: %p,%s
",&adata,adata)
}
func main() {
var scl []string=[]string{"Hi ","My ","Friend "}
fmt.Printf("scl: %p
",&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
",data)
if len(*data)>=0{
(*data)[0]="nono" //这里修改就会影响到外界
}
}
func main() {
var scl *[]string=&[]string{"Hi ","My ","Friend "}
fmt.Printf("scl: %p
",scl)
a(scl)
fmt.Println(scl)
}
scl: 0xc000068440 //地址相同
data1: 0xc000068440
&[nono My Friend ] //函数影响到了外界