Go语言用例Go知识库

golang的struct里面嵌入interface

2018-04-26  本文已影响13人  CodingCode

golang的struct里面嵌入interface

先通过几个例子来说明这样用法。

例子1

定义一个Interface II包含两个函数声明

  1. F1()
  2. F2()

然后定义一个struct SS,它实现了函数F1和F2,这样SS其实就是II的一个实现。

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
}

func (ss *SS) F1() {
}

func (ss *SS) F2() {
}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)
} 

编译运行,输出如下

$ go build && ./main
ss:value=[{0}]
ii:value=[&{0}]

例子2

如果在struct SS中不实现F1和F2,或者只实现F1或者F2,还能不能继续使用呢。
还是前面的代码,我们注释掉F2的定义。

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
}

func (ss *SS) F1() {
}

//func (ss *SS) F2() {
//}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)
}

编译运行

$ go build && ./main
# testinterfacestruct
./main.go:25: cannot use &ss (type *SS) as type II in assignment:
        *SS does not implement II (missing F2 method)

编译器报错,不能把ss赋值给ii,因为SS不是II的实现。

例子3

那么如何解决上述问题呢,嵌入interface的作用就出来了。我们把interface作为struct的一个匿名成员,就可以假设struct就是此成员interface的一个实现,而不管struct是否已经实现interface所定义的函数。

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
    II
}

//func (ss *SS) F1() {
//}

//func (ss *SS) F2() {
//}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)
}

这个例子中,struct SS没有实现interface II的任何一个函数,只是在声明struct的时候把II作为一个匿名成员,此时 var ii II = &ss 赋值语句没有任何错误,可见ss已经被认为是interface II的实现。

所以嵌入interface可以使得一个struct具有interface的接口,而不需要实现interface中的有声明的函数。

例子4

既然没有实现函数,那么如何调用接口的呢?答案是,没有实现肯定是不能调用啊,直接crash了;只能调用已经实现的函数。
还是在上述例子中,我们定义F1,没有实现F2,那么可以正常调用F1,但是不能调用F2

package main

import (
    "fmt"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
    II
}

func (ss *SS) F1() {
    fmt.Printf("in SS::F1()\n")
}

//func (ss *SS) F2() {
//}

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)

    ii.F1()
}

运行结果

ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]
in SS::F1()

如果我们运行F2呢,会出什么结果?

把main函数改成试试:

func main() {
    var ss SS = SS{}
    var ii II = &ss

    fmt.Printf("ss:value=[%v]\n", ss)
    fmt.Printf("ii:value=[%v]\n", ii)

    // ii.F1()
    ii.F2()
}

编译运行:

$ go build && ./main
ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x47d680]

goroutine 1 [running]:
main.(*SS).F2(0xc42000a300)
        <autogenerated>:3 +0x40
main.main()
        /home/.../go/src/main/main.go:33 +0x185

可见编译器成功完成了编译,但是在运行的时候出错了,因为F2函数根本找不到。

例子5

我们分析一个嵌入Interface的实现;在前面我们已经看到struct和interface的内容了。

ss:value=[{0 <nil>}]
ii:value=[&{0 <nil>}]

ss的内容包含一个0值和一个nil值,0值vv的值,那么<nil>推测就是II的值了;增强一下代码:

package main

import (
    "fmt"
    "unsafe"
)

type II interface {
    F1()
    F2()
}

type SS struct {
    vv int
    II
    ww int
}

func (ss *SS) F1() {
    fmt.Printf("in SS::F1()\n")
}

func (ss *SS) F2() {
    fmt.Printf("in SS::F2()\n")
}

func main() {
    var ss SS = SS{vv:1,ww:2}
    var ii II = &ss

    fmt.Printf("ss:size=[%d],value=[%v]\n", unsafe.Sizeof(ss), ss)
    fmt.Printf("ii:size=[%d],value=[%v]\n", unsafe.Sizeof(ii), ii)
}

运行结果:

$ go build && ./main
ss:size=[32],value=[{1 <nil> 2}]
ii:size=[16],value=[&{1 <nil> 2}]

可见ss占用32字节,前8字节和后8字节分别是变量vv和ww,中间的16字节必须是给II的;这是一个占位符,没有具体的值,其值为nil。

这个地方有疑问,为什么是一个nil的占位符。

上一篇 下一篇

猜你喜欢

热点阅读