Golang学习笔记_18——接口
Golang学习笔记_15——range
Golang学习笔记_16——Map
Golang学习笔记_17——方法
文章目录
- 接口
- 1. 定义
- 2. 接口实现
- 3. 空接口
- 4. 类型选择
- 5. 类型断言
- 5.1 基本用法
- 5.2 使用场景
- 5.3 返回值
- 源码
接口
在Go语言中,接口(interface)是一种类型,它规定了对象的行为。接口是一种抽象类型,它定义了一组方法签名,而不包含方法的实现。Go语言的接口通过隐式实现,也就是说,如果一个类型定义了接口中所有方法,那么它就隐式地实现了该接口,而不需要显式地声明。
1. 定义
接口通过type关键字定义,并且接口中的方法没有实现(即没有函数体),只有方法签名。
type 接口名 interface {
方法名1(参数列表1) 返回值列表1
方法名2(参数列表2) 返回值列表2
...
}
举个例子
type Animal interface {
Speak() string
}
2. 接口实现
在Go语言中,一个类型只要实现了接口中的所有方法,它就隐式地实现了该接口。
继续刚刚的例子
type Dog struct {
}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct{}
func (c Cat) Speak() string {
return "Meow!"
}
调用
func MakeAnimalSpeak(animal Animal) string {
return animal.Speak()
}
测试方法
func TestMakeAnimalSpeak(t *testing.T) {
type args struct {
animal Animal
}
tests := []struct {
name string
args args
want string
}{
{
name: "dog",
args: args{
animal: Dog{},
},
want: "Woof!",
},
{
name: "cat",
args: args{
animal: Cat{},
},
want: "Meow!",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := MakeAnimalSpeak(tt.args.animal); got != tt.want {
t.Errorf("MakeAnimalSpeak() = %v, want %v", got, tt.want)
}
})
}
}
输出结果
=== RUN TestMakeAnimalSpeak
=== RUN TestMakeAnimalSpeak/dog
=== RUN TestMakeAnimalSpeak/cat
--- PASS: TestMakeAnimalSpeak (0.00s)
--- PASS: TestMakeAnimalSpeak/dog (0.00s)
--- PASS: TestMakeAnimalSpeak/cat (0.00s)
PASS
3. 空接口
空接口(interface{})是一个特殊的接口,它不包含任何方法。由于所有类型都至少实现了零个方法,因此空接口可以表示任何类型。空接口常用于编写可以处理任意类型值的函数。
// MakeAnythingSpeak empty interface demo
func MakeAnythingSpeak(anything interface{}) {
fmt.Printf("%T\n", anything)
}
测试方法
func TestMakeAnythingSpeak(t *testing.T) {
type args struct {
anything interface{}
}
tests := []struct {
name string
args args
}{
{
name: "num",
args: args{
anything: 3,
},
},
{
name: "string",
args: args{
anything: "hello",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
MakeAnythingSpeak(tt.args.anything)
})
}
}
输出结果
=== RUN TestMakeAnythingSpeak
--- PASS: TestMakeAnythingSpeak (0.00s)
=== RUN TestMakeAnythingSpeak/num
int
--- PASS: TestMakeAnythingSpeak/num (0.00s)
=== RUN TestMakeAnythingSpeak/string
string
--- PASS: TestMakeAnythingSpeak/string (0.00s)
PASS
4. 类型选择
类型选择(type switch)用于根据接口值的动态类型执行不同的代码分支。
// TypeSwitchDemo type switch demo
func TypeSwitchDemo(anything interface{}) {
switch anything.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
default:
fmt.Println("unknown")
}
}
测试方法
func TestTypeSwitchDemo(t *testing.T) {
type args struct {
anything interface{}
}
tests := []struct {
name string
args args
}{
{
name: "num",
args: args{
anything: 3,
},
},
{
name: "string",
args: args{
anything: "hello",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
TypeSwitchDemo(tt.args.anything)
})
}
}
输出结果
=== RUN TestTypeSwitchDemo
=== RUN TestTypeSwitchDemo/num
int
=== RUN TestTypeSwitchDemo/string
string
--- PASS: TestTypeSwitchDemo (0.00s)
--- PASS: TestTypeSwitchDemo/num (0.00s)
--- PASS: TestTypeSwitchDemo/string (0.00s)
PASS
5. 类型断言
在Go语言中,类型断言(Type Assertion)是一种用于检测接口值具体类型的方式,并可以从中提取该值。这对于处理实现了多个接口的类型或者当你有一个接口类型的变量但想以它具体底层类型的身份来处理它时非常有用。
5.1 基本用法
x.(T)
5.2 使用场景
-
从接口类型中提取具体类型的值:
当你有一个接口类型变量,但你知道或希望它以一个具体类型的身份被处理时,可以使用类型断言。 -
类型检查和转换:
在不确定一个接口类型变量存储的是哪种具体类型时,可以使用类型断言来检查并转换到期望的类型。
5.3 返回值
- 类型转换成功时返回的值。
- 一个布尔值,表示断言是否成功。
例子:
// TypeAssertionDemo1 Type Assertion Demo1
func TypeAssertionDemo1() {
var i interface{} = "Hello, World!"
// 类型断言
s, ok := i.(string)
if ok {
fmt.Println("i 是字符串类型,值为:", s)
} else {
fmt.Println("i 不是字符串类型")
}
// 尝试将 i 断言为 int 类型,这将失败
n, ok := i.(int)
if ok {
fmt.Println("i 是 int 类型,值为:", n)
} else {
fmt.Println("i 不是 int 类型")
}
}
测试方法
func TestTypeAssertionDemo1(t *testing.T) {
TypeAssertionDemo1()
}
输出结果
=== RUN TestTypeAssertionDemo1
i 是字符串类型,值为: Hello, World!
i 不是 int 类型
--- PASS: TestTypeAssertionDemo1 (0.00s)
PASS
例子2
// TypeAssertionDemo Type Assertion Demo2
func TypeAssertionDemo(anything interface{}) {
if v, ok := anything.(int); ok {
fmt.Println(v)
}
}
测试方法
func TestTypeAssertionDemo(t *testing.T) {
type args struct {
anything interface{}
}
tests := []struct {
name string
args args
}{
{
name: "num",
args: args{
anything: 3,
},
},
{
name: "func",
args: args{
anything: sayHello,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
TypeAssertionDemo(tt.args.anything)
})
}
}
输出结果
=== RUN TestTypeAssertionDemo
--- PASS: TestTypeAssertionDemo (0.00s)
=== RUN TestTypeAssertionDemo/num
3
--- PASS: TestTypeAssertionDemo/num (0.00s)
=== RUN TestTypeAssertionDemo/func
--- PASS: TestTypeAssertionDemo/func (0.00s)
PASS
源码
// interface_demo.go 文件
package interface_demo
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct {
}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct{}
func (c Cat) Speak() string {
return "Meow!"
}
func MakeAnimalSpeak(animal Animal) string {
return animal.Speak()
}
// MakeAnythingSpeak empty interface demo
func MakeAnythingSpeak(anything interface{}) {
fmt.Printf("%T\n", anything)
}
// TypeSwitchDemo type switch demo
func TypeSwitchDemo(anything interface{}) {
switch anything.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
default:
fmt.Println("unknown")
}
}
// TypeAssertionDemo1 Type Assertion Demo1
func TypeAssertionDemo1() {
var i interface{} = "Hello, World!"
// 类型断言
s, ok := i.(string)
if ok {
fmt.Println("i 是字符串类型,值为:", s)
} else {
fmt.Println("i 不是字符串类型")
}
// 尝试将 i 断言为 int 类型,这将失败
n, ok := i.(int)
if ok {
fmt.Println("i 是 int 类型,值为:", n)
} else {
fmt.Println("i 不是 int 类型")
}
}
// TypeAssertionDemo Type Assertion Demo2
func TypeAssertionDemo(anything interface{}) {
if v, ok := anything.(int); ok {
fmt.Println(v)
}
}
// interface_demo_test.go 文件
package interface_demo
import (
"testing"
)
func TestMakeAnimalSpeak(t *testing.T) {
type args struct {
animal Animal
}
tests := []struct {
name string
args args
want string
}{
{
name: "dog",
args: args{
animal: Dog{},
},
want: "Woof!",
},
{
name: "cat",
args: args{
animal: Cat{},
},
want: "Meow!",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := MakeAnimalSpeak(tt.args.animal); got != tt.want {
t.Errorf("MakeAnimalSpeak() = %v, want %v", got, tt.want)
}
})
}
}
func TestMakeAnythingSpeak(t *testing.T) {
type args struct {
anything interface{}
}
tests := []struct {
name string
args args
}{
{
name: "num",
args: args{
anything: 3,
},
},
{
name: "string",
args: args{
anything: "hello",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
MakeAnythingSpeak(tt.args.anything)
})
}
}
func TestTypeSwitchDemo(t *testing.T) {
type args struct {
anything interface{}
}
tests := []struct {
name string
args args
}{
{
name: "num",
args: args{
anything: 3,
},
},
{
name: "string",
args: args{
anything: "hello",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
TypeSwitchDemo(tt.args.anything)
})
}
}
func TestTypeAssertionDemo1(t *testing.T) {
TypeAssertionDemo1()
}
func TestTypeAssertionDemo(t *testing.T) {
type args struct {
anything interface{}
}
tests := []struct {
name string
args args
}{
{
name: "num",
args: args{
anything: 3,
},
},
{
name: "func",
args: args{
anything: sayHello,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
TypeAssertionDemo(tt.args.anything)
})
}
}
func sayHello() {
}