为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我无法在界面中访问此字段?

为什么我无法在界面中访问此字段?

Go
MMTTMM 2022-01-04 10:08:04
我试图更好地理解接口,但不明白为什么s没有 field Width。我的例子在这里:package mainimport "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有宽度但s没有?我得到的确切错误是:s.Width undefined (type shapes has no field or method Width)
查看完整描述

2 回答

?
慕桂英4014372

TA贡献1871条经验 获得超13个赞

shapesinterface 是*rect实现的东西,但它不是一个具体的 type *rect。就像任何接口一样,它是一组方法,允许任何满足它的类型通过,就像给它一个临时的访客贴纸以登上建筑物。


例如,如果有一只猴子(或者说它的价值是一只海豚),它可以行动并做人类所能做的一切,那么在 Go 的大楼里,他可以越过守卫,登上电梯。然而,这并不使他在基因上成为人类。


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完全可以通过 asshapes但它没有Width属性,因为它不是*rect. 接口不能直接访问底层类型的属性,而只能通过实现的方法集来访问。为了访问属性,需要在接口上进行类型断言,以便实例成为具体类型:


var r *rect


// Verify `s` is in fact a `*rect` under the hood

if r, ok := s.(*rect); ok {

        fmt.Println(r.Width)

}

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


查看完整回答
反对 回复 2022-01-04
?
SMILET

TA贡献1796条经验 获得超4个赞

s 是 shape 接口的实现者,但在 for 循环中没有输入为 rect。如果您执行类型断言以强制 s 为具体类型,如下所示:

s.(*rect).Width

你会得到你想要的。

但是,您需要小心混合这样的具体类型和接口。


查看完整回答
反对 回复 2022-01-04
  • 2 回答
  • 0 关注
  • 229 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号