Dra-M Dra-M
首页
技术
冥思
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

莫小龙

保持理智,相信未来。
首页
技术
冥思
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java基础

  • Spring

  • 微服务

  • Elasticsearch

  • Golang

    • GitLab私服+Go Modules踩坑经验(SSH自定义端口)
    • 【代码片段】我使用的Gin中间处理器(自定义异常处理、日志打印、traceId、跨域配置)
    • 【Java转Go】如何理解Go中的值类型、引用类型、nil
    • 【Java转Go】如何理解面向对象,怎么把Golang用成面向对象的样子
  • 实用工具

  • Bash

  • DevOps系列

  • 技术
  • Golang
莫小龙
2022-12-03

【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);
    }
1
2
3
4
5
6
7
8
9
func main() {
	i := 1
	j := i
	i = 2
	//2
	println(i)
	//1
	println(j)
}
1
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);
    }
1
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);
    }
1
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)
}
1
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)
}
1
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是空的意思。


#Golang
上次更新: 12/3/2022
【代码片段】我使用的Gin中间处理器(自定义异常处理、日志打印、traceId、跨域配置)
【Java转Go】如何理解面向对象,怎么把Golang用成面向对象的样子

← 【代码片段】我使用的Gin中间处理器(自定义异常处理、日志打印、traceId、跨域配置) 【Java转Go】如何理解面向对象,怎么把Golang用成面向对象的样子→

最近更新
01
【代码片段】我使用的Gin中间处理器(自定义异常处理、日志打印、traceId、跨域配置)
12-03
02
【Java转Go】如何理解面向对象,怎么把Golang用成面向对象的样子
12-02
03
GitLab私服+Go Modules踩坑经验(SSH自定义端口)
08-31
更多文章>
Theme by Vdoing | Copyright © 2019-2023 Dra-M | 冀ICP备2021002204号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式