Golang学习笔记_18——接口

Golang学习笔记_15——range
Golang学习笔记_16——Map
Golang学习笔记_17——方法



接口

在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 使用场景
  1. 从接口类型中提取具体类型的值:
    当你有一个接口类型变量,但你知道或希望它以一个具体类型的身份被处理时,可以使用类型断言。

  2. 类型检查和转换:
    在不确定一个接口类型变量存储的是哪种具体类型时,可以使用类型断言来检查并转换到期望的类型。

5.3 返回值
  1. 类型转换成功时返回的值。
  2. 一个布尔值,表示断言是否成功。

例子:

// 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() {

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值