• 请不要在回答技术问题时复制粘贴 AI 生成的内容
jiekeop
V2EX  ›  程序员

新人求教一个 Go 语言问题

  •  
  •   jiekeop · Jun 19, 2023 · 1922 views
    This topic created in 1080 days ago, the information mentioned may be changed or developed.
    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 也成功了。百思不得其解

    zxdstyle
        1
    zxdstyle  
       Jun 19, 2023   ❤️ 1
    renyijiu
        2
    renyijiu  
       Jun 19, 2023   ❤️ 1
    var 定义之后没有赋值,默认是一个 zero value, 其中 name 字段是 string ,所以是个空字符串。
    serco
        3
    serco  
       Jun 19, 2023
    没用过 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}
    ```
    nickxudotme
        4
    nickxudotme  
       Jun 19, 2023
    在我的印象里声明一个变量的时候都会自动初始化为零值,完全不要操心
    Nazz
        5
    Nazz  
       Jun 19, 2023
    go 有空值安全特性
    dobelee
        6
    dobelee  
       Jun 19, 2023   ❤️ 1
    这个不是指针类型。下面这个才是。你的写法是初始化零值。
    var service *MyService
    moqimoqide
        7
    moqimoqide  
       Jun 19, 2023
    帮问了一下 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
        8
    buffzty  
       Jun 19, 2023   ❤️ 1
    var service MyService
    等于 var service = MyService{}
    等于 service:= MyService{}
    jiekeop
        9
    jiekeop  
    OP
       Jun 19, 2023
    谢谢各位解答,明白了
    LeegoYih
        10
    LeegoYih  
       Jun 19, 2023
    Go 反直觉的地方多了去了,学 Go 不能代入其他语言的思维。
    无忌,你忘干净了吗?
    lilei2023
        11
    lilei2023  
       Jun 19, 2023
    这个我刚学也比较懵
    Cola98
        12
    Cola98  
       Jun 19, 2023
    因为这是一个浅拷贝,第一个 name1 没有赋值,所以就给了默认值就是"",接着你 name2 为 zhangsan ,name3 会接着用之前的值
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   930 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 62ms · UTC 21:39 · PVG 05:39 · LAX 14:39 · JFK 17:39
    ♥ Do have faith in what you're doing.