• hiyanxu 置顶
    2018-12-19
    老师,您好:
    我在这篇文章中看到您说,给接口类型变量赋值时传递的都是副本,我测试了,确实是不会改变被赋值后的接口类型变量。
    后面,我重新给Pet接口加上了SetName()方法,然后让*Dog类型实现了该Pet接口,然后声明并初始化了一个d,将d的地址&d赋值给Pet类型的接口变量:
    d := Dog{name: "little dog"}
    var pet Pet = &d
    此时,我去修改了d的name字段:
    d.SetName("big dog")
    运行后发现输出不仅d的name字段变为了“big dog”,同样pet接口变量也变成了“big dog”。
    在此时我是不是可以说,传递给pet变量的同样是&d的一个指针副本,因为传递的是副本,所以无论是指针还是值,都可以说是浅复制;且由于传递的是指针(虽然是副本),但还是会对指向的底层变量做修改。
    请问老师,我上面的推断是正确的吗?
    另外我想说真的每篇文章都需要好好研读啊,看一篇得两个小时,里面好多干货,谢谢老师!
    展开

    作者回复: 没错,虽然是副本,但却是指针的副本,SetName又是指针方法。所以综合起来这种修改就生效了。

    另外这类副本都是浅表复制。也没错。

    
     11
  • xlh
    2018-09-13
    大神,每篇文章前能先解答上次留的问题吗?思考过后有个答案,有错思之,无错加勉
    
     60
  • extraterrestrial!!
    2018-09-16
    有个疑问,go里面一个类型实现了接口所有的方法,才算该接口类型,但并没有语法显式说明这个类型实现了哪个接口(例如java中有implements), 这样看别人代码的时候,碰到一个类型,无法知道这个类型是不是实现了一个接口,除非类型和接口写在一个文件,然后还要自己一个一个方法去对比。有比较快的方法可以知道当前类型实现了哪些接口么?
     3
     30
  • 追梦
    2018-09-17
    关于思考题,如果我们把一个值为nil的某个实现类型的变量赋给了接口变量,在这个接口变量上仍然可以访问其方法,但无法访问其属性。使用时需要注意:如果涉及到变量属性,这些属性值均为默认值。
    
     12
  • Aaron
    2018-09-20
    文章中demo32.go demo31.go可不可以直接贴出来
    
     10
  • asdf100
    2018-09-12
    golang中,结构体类型struct包裹的是它的字段声明,而接口类型interface包裹的是它的方法定义。
    
     8
  • 志鑫
    2019-05-10
    思考题,要看实现类型是值类型还是指针类型;
        var d2 Dog
        var p2 Pet = d2
        if p2 != nil {
            fmt.Println("p2.Name()", p2.Name())
        }

        var d3 *Dog
        var p3 Pet = d3
        if p3 != nil {
            fmt.Println("p3.Name()", p3.Name()) //运行是报错,panic: value method main.Dog.Name called using nil *Dog pointer

        }
    展开

    作者回复: 这主要是因为 Dog 和 *Dog 的零值是完全不同的,前者是 Dog{} ,而后者是 nil 。

    
     6
  • 吉他
    2019-05-25
    关于思考题,如果我们把一个值为nil的某个实现类型的变量赋给了接口变量,那么在这个接口变量上仍然可以调用该接口的方法吗?
    可以的,不过方法内不能使用实现类型内的变量,并且方法接收者必须是指针类型

    作者回复: 对的,对于指针方法来说是这样。

    
     5
  • undifined
    2018-09-12
    因为将 nil 实际类型的变量赋值给接口变量,会包装为 iface 实例,这个实例不为空,所以依然可以调用接口的方法,但是通过方法访问变量的属性,则会返回空
     1
     5
  • colben
    2018-09-13
    package main

    import (
        "fmt"
    )

    type Person struct {
        name string
        age uint8
    }

    // use computer
    type ComputerOper interface {
        TurnOnComputer()
        TurnOffComputer()
    }

    // use chrome
    type ChromeOper interface {
        ComputerOper
        TurnOnChrome()
        TurnOffChrome()
    }

    // turn on computer
    func (p *Person) TurnOnComputer() {
        fmt.Println("Power on computer and boot OS.")
    }

    // turn off computer
    func (p Person) TurnOffComputer() {
        fmt.Println("Shutdown OS and power off computer.")
    }

    // start chrome
    func (p *Person) TurnOnChrome() {
        fmt.Println("Start web browser chrome.")
    }

    // stop chrome
    func (p Person) TurnOffChrome() {
        fmt.Println("Stop web browser chrome.")
    }

    // someone use chrome
    func UseChrome(user ChromeOper) {
        user.TurnOnComputer()
        user.TurnOnChrome()
    // 下面两个是"值方法", 空指针panic
    // user.TurnOffChrome()
    // user.TurnOffComputer()
    }

    func main() {
        var user *Person
        UseChrome(user)
    }

    // 变量本身肯定读写不了,值方法在调用时要复制一个副本,所以也用不了,就剩下指针方法了。
    展开
    
     4
  • 俊杰
    2019-03-20
    老师您好,有个地方不理解,对象赋值给接口后,为什么判等操作返回的是true呢?比如上面的例子:pet = dog之后紧接着判断pet == dog,返回的是true,按上面的说法,赋值后不是应该被包装成了一个iface吗?这里的判等操作到底是依据什么来判断的呢?麻烦老师解释一下,谢谢~

    作者回复: 你可以参照Go语言规范中的说明:https://golang.google.cn/ref/spec#Comparison_operators,请注意下面这句:

    A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t's dynamic type is identical to X and t's dynamic value is equal to x.

     1
     3
  • Arthur.Li
    2018-09-21
    方法签名在这里是指什么呀?我看定义说是方法名称和一个参数列表(方法的参数的顺序和类型)组成。
    文章里面写的两个条件是方法签名一致和方法名一致,所以有些疑惑了

    作者回复: 方法签名严格来说不包含方法名。

     1
     2
  • Michael
    2018-09-17
    这结课终于让我明白了 reflect 包中,reflect.Type 和 reflect.Value 存在的意义,茅塞顿开啊!

    接口变量的值并不等同于这个可被称为动态值的副本。它会包含两个指针,一个指向动态值,一个指向动态类型。

    关于思考题,我试验之后是不可以的,因为在调用的时候没有接收者,还请老师指正
    
     2
  • CcczzZ
    2020-01-03
    重点
    * 接口的基础知识,什么是接口?
    * 怎么判断一个数据类型是一个接口的实现?
    * 接口变量的动态值、动态类型、静态类型都是什么?
    * 当为一个接口变量赋值会发生什么?赋值为一个变量,变量值是 nil 时,接口变量的值是 nil 么?
    * 接口变量的值在什么情况下才真正为nil ?
    * 怎样实现接口之间的组合?
    * 进阶:接口变量的数据结构 iface ?

    知识点:
    1. 在 Go 语言中,说到接口一般都指的是 接口类型。接口类型是无法被实例化的(new、make 函数等),且如果没有数据类型作为接口的实现,那么接口的值就是不存在的
    2. 那怎么判断一个数据类型是否就是接口的实现呢?对于一个数据类型,只要它的方法集实现了所有接口中的所有方法(方法签名和名称要完全一致), 就可以认为该数据类型是接口的实现类型。
    3. 对于接口变量来说,赋值给接口变量的值可称为它的动态值(实际值),该值的类型可叫做这个类型的动态类型(实际类型),静态类型就是接口变量的原始类型。
    4. 基础:当使用一个变量给两外一个变量赋值,那么真正赋值给后者的,是前者值的一个副本,并不是原来的那个值;接口变量实例是一个特殊数据结构iface,包含一个指向类型信息的指针和一个指向动态值的指针。赋值给接口变量的值为另一个变量的 nil 值时,这个接口变量其实不是个nil值
    5. 怎样才能让一个接口变量的值真正为nil呢?要么只声明它但不做初始化,要么直接把字面量nil赋给它
    6. 接口类型的嵌入可实现接口的组合
    7. 数据结构iface,包含一个指向类型信息的指针和一个指向动态值的指针
    展开
    
     1
  • 兴小狸
    2019-08-03
    接口中声明多个方法,有的方法有返回值,有的是没有的。当一个类实现这些接口时,要怎么知道是传值接收者,还是指针接收者呢?

    作者回复: 这与方法有没有返回值没有关系啊。值方法还是指针方法应该是类型定义者考虑的事情。作为使用者,你可以先假定方法的定义是正确的(可以使程序正常工作)。

    回到你最后的问题。你可以看源码,也可以用 reflect 包里的 API 进行探查(不过比较麻烦)。不过我觉得通常没必要这么做。

    
     1
  • 枫林火山
    2019-03-28
    老师,您好,在demo34.go 中我本意是想尝试用interface做内嵌字段来显式表明一个struct的接口能力的。 但是这过程中发现,如果我在Dog中内嵌了Animal接口,然后注释掉Dog的ScientificName实现,line37 - 45 如下
    type Dog struct {
        Animal
        PetTag
        scientificName string
    }

    // func (dog Dog) ScientificName() string {
    //     return dog.scientificName
    // }
    运行代码结果依然是
    PetTag implements interface Named: true
    Dog implements interface Animal: true
    Dog implements interface Named: true
    Dog implements interface Pet: true
    老师能否讲解下这是Go语言的静态检查不完善还是别有深意,我这样使用接口内嵌来表明一个Struct的能力,这样是不是有问题,正确的声明方式是什么?
    展开

    作者回复: 郝林回复:首先,你要明白在Dog里内嵌Animal意味着什么。这意味着Dog类型中包含了一个Animal类型的匿名字段。正是由于这个匿名字段,Dog类型就包含了实现Animal接口所需的所有方法,只不过你并没有为这个匿名字段赋值而已。但是这个字段就摆在那儿了,匿名字段Animal的方法照样会融入Dog的方法集合。这是一个不争的事实,所以类型判断的时候照样会返回true。实际上,单从方法集合融入的这个方面讲,这与Dog内嵌PetTag是一样的。

    这样的嵌入方式是可以的。当你要做部件动态装配的时候可以这么做,不论是嵌入接口类型还是嵌入非接口类型。当然了,内嵌接口类型会更加灵活一些,因为你可以为这个匿名字段赋予不同的实现值。

    
     1
  • Garry
    2018-12-11
    思考题:
    可以通过接口变量调用,但需要注意实现的方法中不能出现访问类型属性的操作,会报空指针解引用错误。
    
     1
  • Geek_1b0d68
    2018-09-18
    由于把值为nil的变量赋值给了接口变量,接口变量在调用时只能调用该实现类型的指针方法,而无法调用值方法。为什么值方法只能实现了该类型的对象或者对象指针才能够调用?
    
     1
  • 兔子高
    2018-09-12
    你好,请问分别在什么情况下使用值方法和什么情况下使用引用方法呢

    作者回复: 需要改动值内部数据的时候必须使用指针方法。其他时候就要看接口实现、被嵌入要求等方面了。我觉得一般情况下用指针方法就好了。

    
     1
  • Crush
    2020-01-14
    所有值为nil的变量a只要不是接口变量,a == nil是不是就成立?

    作者回复: 更精确的说法是:除了接口类型以外的所有引用类型的值,只要它的实际值为nil,自然就等于nil。

    多解释两句:对于这些类型,它们的值就是实际值。而接口类型的值与它们不同,会在实际值之外再包一层,正如文中所述。

    
    
我们在线,来聊聊吧