go - 为什么我无法在界面中访问该字段?

标签 go

我试图更好地理解接口(interface),但不理解为什么 s 没有字段 Width。我的example is here :

package main

import "fmt"

type shapes interface {
    setWidth(float64)
}

type rect struct {
    Width float64
}

func (r *rect) setWidth(w float64) {
    r.Width = w
}

var allShapes = map[string]shapes{
    "rect": &rect{},
}

func main() {
    r := &rect{}
    r.setWidth(5)
    fmt.Println(r.Width)  // this works
    for _, s := range allShapes {
        s.setWidth(7)
        fmt.Println(s.Width) // why not???
    }
}

为什么 r 有 Width 而 s 没有?我得到的确切错误是:

s.Width undefined (type shapes has no field or method Width)

最佳答案

shapes 接口(interface)是*rect 实现的,但它不是具体类型*rect。与任何接口(interface)一样,它是一组方法,允许满足它的任何类型通过,就像给它一个临时访客贴纸以上楼。

例如,如果在 Go 的建筑物中有一只猴子(或者海豚,海豚)可以行动并做任何人类可以做的事情,他可以通过 guard 并上电梯。然而,这并不能使他在基因上成为人类。

Go 是静态类型的,这意味着如果没有类型断言或有意识地转换类型,即使是具有相同底层类型的两种类型也不能动态转换或强制转换为另一种类型。

var a int
type myInt int
var b myInt

a = 2
b = 3
b = a         // Error! cannot use a (type int) as type myInt in assignment.
b = myInt(a)  // This is ok.

想象一下这种情况:

type MyInt int
type YourInt int

type EveryInt interface {
        addableByInt(a int) bool
}

func (i MyInt) addableByInt(a int) bool {
    // whatever logic doesn't matter
    return true
}


func (i YourInt) addableByInt(a int) bool {
    // whatever logic doesn't matter
    return true
}

func main() {
    // Two guys want to pass as an int
    b := MyInt(7)
    c := YourInt(2)

    // Do everything an `EveryInt` requires
    // and disguise as one 
    bi := EveryInt(b)
    ci := EveryInt(c)

    // Hey, look we're the same! That's the closest
    // we can get to being an int!
    bi = ci          // This is ok, we are EveryInt brotherhood
    fmt.Println(bi)  // bi is now 2

    // Now a real int comes along saying
    // "Hey, you two look like one of us!"
    var i int
    i = bi           // Oops! bi has been made

    // ci runs away at this point

}

现在回到您的场景——想象一个 *circle 伴随着实现 shapes:

type circle struct {
        Radius float64
}

func (c *circle) setWidth(w float64) {
        c.Radius = w
}

*circle 完全可以作为 shapes 但它没有 Width 属性,因为它不是 *rect。接口(interface)不能直接访问底层类型的属性,只能通过已实现的方法集来访问。为了访问一个属性,接口(interface)上需要一个类型断言,这样实例就变成了一个具体类型:

var r *rect

// Verify `s` is in fact a `*rect` under the hood
if r, ok := s.(*rect); ok {
        fmt.Println(r.Width)
}

这就是为什么像 Go 这样的静态类型语言总是比动态类型语言更快的核心,后者几乎总是使用某种反射来为您动态处理类型强制。

关于go - 为什么我无法在界面中访问该字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36491620/

相关文章:

google-app-engine - 我无法使用 google.golang.org/appengine 模块将 Go 模块部署到 App Engine

docker - 在 docker 中构建 golang 项目 - 在 $GOPATH 或 $GOROOT 中找不到包

go - 注意包含结构的队列中的更改

Json Unmarshal reflect.Type

Golang OpenGL元素缓冲对象无法正确渲染

go - 如何使用urfave/cli实现OptionFlag

go - 通过Golang形成YAML

regex - 在golang中捕获ping命令的结果

go - 自动调整主窗口大小

string - 将字符串转换为 Foo(类型字符串)