当前位置: 首页 > article >正文

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 使用场景
  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() {

}

http://www.kler.cn/a/470350.html

相关文章:

  • UDP -- 简易聊天室
  • jenkins入门6 --拉取代码
  • 数学建模入门——描述性统计分析
  • Haskell语言的多线程编程
  • 使用 Optimum Habana 在 Intel Gaudi 上加速模型训练与推理
  • python 如何调整word 文档页眉页脚
  • 海外云服务器能用来做什么?
  • python 如何调整word 文档页眉页脚
  • 移动电商的崛起与革新:以开源AI智能名片2+1链动模式S2B2C商城小程序为例的深度剖析
  • 培训机构Day23
  • 在 Vue 中使用 @ngageoint/geopackage 实现 GeoPackage 数据处理与可视化
  • 常见转义字符
  • 人工智能安全——联邦学习的安全攻击与防护
  • Map集合
  • QT6编程入门(一)
  • 每日一题:BM2 链表内指定区间反转
  • 分布式搜索引擎之elasticsearch基本使用3
  • 电脑如何无线控制手机?
  • VVenC 编码器源码结构与接口函数介绍
  • 复古柯达胶片电影效果肖像风景街头摄影Lightroom调色预设 Koda Film Preset Pack | Cinematic Presets
  • Django 模型
  • 20250106面试
  • R语言的计算机基础
  • HTML 显示器纯色亮点检测工具
  • Chapter4.1 Coding an LLM architecture
  • CentOS Stream 9上安装配置NFS