【Java转Go】如何理解Go中的值类型、引用类型、nil
Java的赋值和参数传递都是值拷贝,Golang也是如此。
Java的值类型只有8种:long、int、short、byte、float、double、char、boolean。其他所有类型均为引用类型。
Golang的引用类型只有6种:map、pointers、slice、channel、interface、function。其他所有类型,包括struct,均为值类型。
数据类型本质是固定内存大小的别名
数据就是那些内存中代码段,不是0就是1,只不过不同的读取与解释方式让它有了不同的意义(数据类型亦或指令类型) 。这不同的读取与解释的方式,便是类型的本质。
当操作值类型时,是以某一值类型的方式去解释某段内存数据。
当读引用类型时,是以引用的方式解释某段内存空间,再以引用类型的方式解释引用指向的内存空间。
参数传递是一种赋值,将传递的变量赋值给参数变量。
在Java和Golang中赋值都是值拷贝,对拷贝的值操作不会影响原来的值。
public static void main(String[] args) {
int i = 1;
int j = i;
i = 2;
//2
System.out.println(i);
//1
System.out.println(j);
}
2
3
4
5
6
7
8
9
func main() {
i := 1
j := i
i = 2
//2
println(i)
//1
println(j)
}
2
3
4
5
6
7
8
9
当类型为引用类型时,拷贝的是引用,两个引用的值相同,指向同一块内存区域,当操作对应数据时,操作的是同一块数据。
Java不能显式的操作引用,值类型外的都是引用。
public static void main(String[] args) {
MyInt myIntI = new MyInt();
myIntI.num = 1;
MyInt myIntJ = myIntI;
myIntI.num = 2;
//2
System.out.println(myIntI.num);
//2
System.out.println(myIntJ.num);
}
2
3
4
5
6
7
8
9
10
11
这里特殊提一下,Java的包装类(Integer等),会自动拆装箱,意味着Integer本身虽然是引用类型,但赋值操作时会拆箱为基本的int类型,再包装成一个新的Integer传递。
public static void main(String[] args) {
Integer i = 1;
Integer j = i;
i = 2;
//2
System.out.println(i);
//1
System.out.println(j);
}
2
3
4
5
6
7
8
9
Java的String类型则是遵循不可变原则,里面有一些魔法。当你赋值/修改字符串时可能会赋值一个现成缓存的引用,或新创建空间的引用,但永远不会在原有空间上做修改。
Golang可以通过&取到引用,通过对引用*取到所指的数据。
func main() {
//int类型
i := 1
//*int类型
j := &i
i = 2
//2
println(i)
//0xc000061f60
println(&i)
//2
println(*j)
//0xc000061f60
println(j)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
需要强调的是,Golang结构体拷贝,是值拷贝,其中的引用类型拷贝的是引用地址,也就是浅拷贝,这里容易踩坑。
type MyStruct struct {
np *int
n int
}
func main() {
i := 1
myStructI := MyStruct{np: &i, n: 2}
myStructJ := myStructI
//0xc000061f60
println(&myStructI)
//0xc000061f38
println(myStructI.np)
//0xc000061f50
println(&myStructJ)
//0xc000061f38
println(myStructJ.np)
//0xc000061f68
println(&myStructI.n)
//0xc000061f58
println(&myStructJ.n)
*myStructJ.np = 3
myStructJ.n = 4
//3
println(*myStructI.np)
//2
println(myStructI.n)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
空指针,是用引用的方式解释某段值为0的空间。
只有引用类型可能出现空指针。类型声明意味着开辟一块固定大小的内存空间并写满0,任何值类型的全0都是合法默认值(如int的0,bool的false),只有引用的全0是空的意思。