Golang中关于接口和结构的疑问

Golang中关于接口和结构的疑问 你好,我是一名正在学习 Go 语言的计算机工程专业学生。 我有一个关于我的代码的问题。 每次调用函数 foo() 时,其结果都会不断变化。 我无法理解为什么结构体 str 中字段 s 的地址一直在变化。 有人遇到过这种情况吗?

import "fmt"

type str struct {
	s int
	t int
	r int
}

type str2 struct {
	s string
	t string
	r string
}

type inter_face interface {
	foo()
}

func (s str) foo() {
	fmt.Println("Print")
}

func (s str2) foo() {
	fmt.Printf("%v\t%T\t\t\n", &s.r, s)
}

func main() {
	var i inter_face
	a := str{
		s: 100,
		t: 1000,
		r: 10000,
	}
	b := str2{
		s: "string",
		t: "string type",
		r: "string bool",
	}
	i = a
	i.foo()
	i.foo()
	i = b
	i.foo()
	i.foo()
	i.foo()
	i.foo()
	i.foo()
	i.foo()
}

更多关于Golang中关于接口和结构的疑问的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你写的两个方法都是通过值传递其接收者参数 s 的。因此,每次调用时它都会被复制并获得一个新的地址。通常方法会通过引用来调用它们的接收者。试试这个:

func (s *str)foo()…

更多关于Golang中关于接口和结构的疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个关于Go语言中方法接收者和接口实现的常见问题。你观察到的地址变化是因为方法接收者是按值传递的。

在你的代码中,str2foo() 方法接收的是值接收者:

func (s str2) foo() {
    fmt.Printf("%v\t%T\t\t\n", &s.r, s)
}

每次调用 i.foo() 时,Go都会创建一个新的 str2 结构体副本,因此 s.r 的地址每次都会不同。让我们通过一个更清晰的示例来说明:

package main

import "fmt"

type str2 struct {
    s string
    t string
    r string
}

type inter_face interface {
    foo()
}

// 值接收者 - 每次调用都会创建新副本
func (s str2) foo() {
    fmt.Printf("值接收者 - 地址: %p, r地址: %p\n", &s, &s.r)
}

// 指针接收者 - 使用相同的实例
func (s *str2) foo2() {
    fmt.Printf("指针接收者 - 地址: %p, r地址: %p\n", s, &s.r)
}

func main() {
    var i inter_face
    
    b := str2{
        s: "string",
        t: "string type",
        r: "string bool",
    }
    
    // 使用值接收者
    fmt.Println("使用值接收者:")
    i = b
    for j := 0; j < 3; j++ {
        i.foo()
    }
    
    // 使用指针接收者
    fmt.Println("\n使用指针接收者:")
    i = &b
    for j := 0; j < 3; j++ {
        i.foo()
    }
    
    // 直接调用对比
    fmt.Println("\n直接调用对比:")
    fmt.Printf("原始结构体地址: %p\n", &b)
    b.foo()  // 值接收者
    (&b).foo2()  // 指针接收者
}

输出会显示:

  • 使用值接收者时,每次调用都会创建新的副本,地址不同
  • 使用指针接收者时,操作的是同一个实例,地址相同

如果你想让所有调用都操作同一个实例,应该使用指针接收者:

func (s *str2) foo() {
    fmt.Printf("%v\t%T\t\t\n", &s.r, s)
}

// 在main中需要传递指针
i = &b

这就是为什么你看到 s.r 地址不断变化的原因 - 每个方法调用都在操作不同的结构体副本。

回到顶部