新人求教一个 Go 语言问题

2023-06-19 10:29:35 +08:00
 jiekeop
package main

import "fmt"

type MyService struct {
	Name string
}

func (s *MyService) PName() {
	fmt.Printf("name1 	%s\n", s.Name)
	s.Name = "zhangsan"
	fmt.Printf("name2 	%s\n", s.Name)

}

func main() {
	var service MyService
	service.PName()
	fmt.Printf("name3 	%s\n", service.Name)
}
///output
name1   
name2   zhangsan
name3   zhangsan

代码很简单,无法理解的是 var service MyService 。根据我目前看的学习文档,这个只是声明了一个变量,其类型为 MyService ,而没有绑定到任何内存区域,为什么后续的方法调用没出现空指针报错呢.赋值 Name 也成功了。百思不得其解

1296 次点击
所在节点    程序员
12 条回复
zxdstyle
2023-06-19 10:37:28 +08:00
renyijiu
2023-06-19 10:38:15 +08:00
var 定义之后没有赋值,默认是一个 zero value, 其中 name 字段是 string ,所以是个空字符串。
serco
2023-06-19 10:38:16 +08:00
没用过 go ,随便看了一下,你说的这句实际上已经是实例化了一个 struct

看这个的案例 https://www.tutorialsteacher.com/go/struct#:~:text=In%20Go%20lang%2C%20struct%20(structure,the%20type%20and%20struct%20keywords.

You can declare an instance and assign values later on using a dot, as shown below.

```
var s4 Student
s4.id = 4
s4.name = "Abdul"
s4.grade = 8

fmt.Println(s4) //output: {4 Abdul 8}

var s5 Student
s5.name = "Sachin"

fmt.Println(s5) //output: {0 Sachin 0}
```
NX2023
2023-06-19 10:41:39 +08:00
在我的印象里声明一个变量的时候都会自动初始化为零值,完全不要操心
Nazz
2023-06-19 10:42:04 +08:00
go 有空值安全特性
dobelee
2023-06-19 10:44:55 +08:00
这个不是指针类型。下面这个才是。你的写法是初始化零值。
var service *MyService
moqimoqide
2023-06-19 10:45:29 +08:00
帮问了一下 gpt:

在 Go 语言中,如果结构体类型的实例被声明为值类型变量(而不是指针类型变量)时,在调用该结构体类型的方法时,会自动进行值拷贝( pass by value )。换言之,值类型变量作为一个参数传递给方法时,方法会获取该值类型变量的一份拷贝,当方法需要修改该结构体类型实例的值时,它修改的只是拷贝中的相应值,而不是原来的变量。所以调用顺序如下:

1. 执行 service.PName() 方法时,会将 MyService 类型的 service 的一份拷贝传递给 PName() 方法。

2. 在 PName() 方法中,首先打印出 s.Name 的值,由于此时 Name 字段还没有被初始化,因此打印出的结果为空字符串。

3. 接下来,将 s.Name 的值更改为 "zhangsan"。

4. 继而,打印出 s.Name 的值,此时 Name 字段的值已经被更改为 "zhangsan",因此打印出的结果为 "zhangsan"。

5. PName() 方法执行结束,返回到 main() 函数中。

6. 在 main() 函数中,打印出 service.Name 的值,此时打印出的是 "zhangsan"。

因此,在你的代码中,var service MyService 声明了一个值类型的 MyService 变量,该结构体实例会被分配内存空间并初始化(其中包括 Name 字段),但在调用 PName() 方法时,会将 service 的一份拷贝传递给该方法,因此执行 PName() 方法会修改拷贝中的 Name 字段的值,但不会影响原来的 service 变量。
buffzty
2023-06-19 10:51:23 +08:00
var service MyService
等于 var service = MyService{}
等于 service:= MyService{}
jiekeop
2023-06-19 10:54:06 +08:00
谢谢各位解答,明白了
LeegoYih
2023-06-19 10:58:25 +08:00
Go 反直觉的地方多了去了,学 Go 不能代入其他语言的思维。
无忌,你忘干净了吗?
lilei2023
2023-06-19 11:28:52 +08:00
这个我刚学也比较懵
Cola98
2023-06-19 13:31:06 +08:00
因为这是一个浅拷贝,第一个 name1 没有赋值,所以就给了默认值就是"",接着你 name2 为 zhangsan ,name3 会接着用之前的值

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/949872

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX