首页 >后端开发 >Golang >为什么 Go 的 `greeter` 接口不能分配一个 `tourGuide` 值,但可以分配一个指向 `tourGuide` 的指针?

为什么 Go 的 `greeter` 接口不能分配一个 `tourGuide` 值,但可以分配一个指向 `tourGuide` 的指针?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-11-20 01:38:03221浏览

Why can't a Go `greeter` interface be assigned a `tourGuide` value, but can be assigned a pointer to a `tourGuide`?

满足接口的 Go Struct 方法类型

给出以下 Go 代码示例:

package main

import "fmt"

type greeter interface {
    hello()
    goodbye()
}

type tourGuide struct {
    name string
}

func (t tourGuide) hello() {
    fmt.Println("Hello", t.name)
}

func (t *tourGuide) goodbye() {
    fmt.Println("Goodbye", t.name)
}

func main() {
    var t1 tourGuide = tourGuide{"James"}
    t1.hello()   // Hello James
    t1.goodbye() // Goodbye James (same as (&t1).goodbye())

    var t2 *tourGuide = &tourGuide{"Smith"}
    t2.hello()   // Hello Smith
    t2.goodbye() // Goodbye Smith (same as (*t2).hello())

    // illegal: t1 is not assignable to g1 (why?)
    // var g1 greeter = t1

    var g2 greeter = t2
    g2.hello()   // Hello Smith
    g2.goodbye() // Goodbye Smith
}

在上面的代码中,您可以使用tourGuide类型的变量(t1)或指向tourGuide的指针(t2)调用structtourGuide的两个方法。然而,当实现接口时,情况就会发生变化。 greeter 接口类型的变量可从指向tourGuide 的指针分配,但不能从tourGuide 值分配。为什么会出现这种情况?

接收器类型和值语义

要理解原因,了解接收器类型和值语义的概念很重要。 Go 中的方法可以有一个值接收器或一个指针接收器。值接收器方法在值的副本上调用,而指针接收器方法在原始值上调用。

复制值时,它会创建原始值的新独立副本。对副本所做的任何修改都不会影响原始值。这称为值语义。

在tourGuide 示例中,hello 方法有一个值接收器,而goodbye 方法有一个指针接收器。当您调用 t1.hello() 时,会创建 t1 的副本,并在该副本上调用 hello 方法。当你调用 t1.goodbye() 时,goodbye 方法会在原始 t1 值上调用。

接口和值语义

Go 中的接口是通过值语义实现的。这意味着当将值分配给接口时,会创建该值的副本。对于指针接收器方法,这意味着该值的副本没有地址,因此无法在其上调用该方法。

例如,当您将 t1 分配给 g1 时(其中是一个接口值)在以下代码行中:

// illegal: t1 is not assignable to g1 (why?)
// var g1 greeter = t1

创建了t1的副本,并在副本上实现了hello和goodbye方法。但是,由于副本没有地址,因此无法对其调用 goodbye 方法。

相反,当您在以下代码行中将 t2 分配给 g2 时:

var g2 greeter = t2

创建t2(指向tourGuide的指针)的副本,并在该指针的副本上实现hello和goodbye方法。在这种情况下,指针的副本有一个地址,因此可以在其上调用 goodbye 方法。

结论

综上所述,greeter 接口类型的变量是可赋值的原因从指向tourGuide的指针而不是从tourGuide值是因为接口是通过值语义实现的。当将值分配给接口时,会创建该值的副本,如果接口的方法有指针接收器,则无法在副本上调用它们,因为副本没有地址。

以上是为什么 Go 的 `greeter` 接口不能分配一个 `tourGuide` 值,但可以分配一个指向 `tourGuide` 的指针?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn