Go-学会 Go 中 interface 的基本使用

本节重点:

  • 学会 Go 中 interface 的基本使用

在 Go 中,接口类型是一种抽象类型,是方法的集合,其他类型实现了这些方法就是实现了这个接口。

声明和实现接口

在 Go 中接口的声明如下:

/* 定义接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

简单示例

现在我们通过一个简单的示例来看是如何创建接口并实现它:

package main
 
import (  
    "fmt"
)
 
//interface definition
type VowelsFinder interface {  
    FindVowels() []rune
}
 
type MyString string
 
//MyString implements VowelsFinder
func (ms MyString) FindVowels() []rune {  
    var vowels []rune
    for _, rune := range ms {
        if rune == 'a' || rune == 'e' || rune == 'i' || rune == 'o' || rune == 'u' {
            vowels = append(vowels, rune)
        }
    }
    return vowels
}
 
func main() {  
    name := MyString("Sam Anderson")
    var v VowelsFinder
    v = name // possible since MyString implements VowelsFinder
    fmt.Printf("Vowels are %c", v.FindVowels())
 
}

在上面程序第8行中,创建了一个名为 VowelsFinder 的接口类型,它有一个方法 FindVowels() []rune

在下一行中创建一个类型 MyString 它只是 string 的包装类。

在第15行中,我们将方法 FindVowels()[]rune 添加到接收方类型 MyString 中。现在 MyString 被认为实现了 VowelsFinder 接口。这与 Java 等其他语言非常不同,在 Java 中,类必须使用 implements 关键字显式地声明它实现了接口。如果类型包含接口中声明的所有方法,则 go 和 go 接口将隐式实现。

在第28行,我们将 MyString 类型的 name 赋给 v 类型的 VowelsFinder。这是可能的,因为 MyString 实现了 VowelsFinder。下一行调用 MyString 类型上的 FindVowels 方法,并打印字符串中所有的元音 Sam Anderson。这个程序输出的 Vowels are [a e o]

这样已经创建并实现了第一个接口。

空接口

一个没有方法的接口称为空接口。它表示为 interface{}。由于空接口没有任何方法,所以所有类型都实现空接口。

package main
 
import (  
    "fmt"
)
 
func describe(i interface{}) {  
    fmt.Printf("Type = %T, value = %v\n", i, i)
}
 
func main() {  
    s := "Hello World"
    describe(s)
    i := 55
    describe(i)
    strt := struct {
        name string
    }{
        name: "Naveen R",
    }
    describe(strt)
}

在上面的程序中第 7 行,describe(i interface{}) 函数接受一个空接口作为参数,因此它可以传递任何类型。
我们将字符串、int 和 结构体分别传递给第 13、15 和 21 行中的 describe 函数。这个程序打印

类型断言

类型断言用于提取接口的基础值。

i.(T)是用于获取具体类型为T的接口i的底层值的语法。
一个程序值一千字😀。让我们为类型断言写一个。

package main
 
import (  
    "fmt"
)
 
func assert(i interface{}) {  
    s := i.(int) //get the underlying int value from i
    fmt.Println(s)
}
func main() {  
    var s interface{} = 56
    assert(s)
}

第12行中的 s 的具体类型是 int。我们使用第8行中的 i.(int) 语法来获取 i 的底层 int 值。这个程序打印 56
如果上面程序中的具体类型不是 int 会发生什么?好吧,让我们来了解一下。

package main
 
import (  
    "fmt"
)
 
func assert(i interface{}) {  
    s := i.(int) 
    fmt.Println(s)
}
func main() {  
    var s interface{} = "Steven Paul"
    assert(s)
}

在上面的程序中,我们将具体类型strings传递给assert函数,试图从中提取 int 值。这个程序会因为这个问题而报错panic: interface conversion: interface {} is string, not int
为了解决上述问题,我们可以使用语法

v, ok := i.(T)

如果 i 的具体类型是 T,那么 v 的值就是 iok 为 true

如果 i 的具体类型不是 T,那么 ok 将是 falsev 将是类型 T 的零值,程序不会报错。

package main
 
import (  
    "fmt"
)
 
func assert(i interface{}) {  
    v, ok := i.(int)
    fmt.Println(v, ok)
}
func main() {  
    var s interface{} = 56
    assert(s)
    var i interface{} = "Steven Paul"
    assert(i)
}

Steven Paul被传递给assert函数时,ok 将为 false,因为i具体类型不是int,并且v为 0值。该程序将打印:

56 true  
0 false 

注意:

  • 上面所有示例接口都是使用值接收器实现的。也可以使用指针接收器来实现接口。但是会有一些微妙的区别?动手试试!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极简网络科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值