GO语言学习(13)接口interface

发布于:2025-04-04 ⋅ 阅读:(19) ⋅ 点赞:(0)

🌈前言

        在Go语言中,接口(interface)是方法的集合,它允许我们定义一组方法但不实现它们,任何类型只要实现了这些方法,就被认为是实现了该接口。

结构体(Struct) 接口(Interface)
定义“是什么”(数据长啥样) 定义“能做什么”(有哪些方法)
存储具体数据 存储方法的约定
直接实例化 不能直接实例化,必须由具体类型实现

1.接口的声明与使用🌻

🔥定义一个简单接口:

type Shape interface {
    Area() float64
    Perimeter() float64
}
  • Shape 是一个接口,定义了两个方法:Area 和 Perimeter
  • 任意类型只要实现了这两个方法,就被认为实现了 Shape 接口。

🔥实现接口: 类型通过实现接口要求的所有方法来实现接口。

package main
import "fmt"

type Student struct {      // 定义 Student 结构体
	Name string
	Age  int
}

type Person interface {         // 定义 Person 接口
	GetName() string
	GetAge() int
}

func (s Student) GetName() string {    // 实现对应接口方法
	return s.Name
}
func (s Student) GetAge() int {
	return s.Age
}

func main() {
	s1 := Student{                     // 初始化结构体
		Name: "Sun",
		Age:  18,
	}
	var p1 Person = s1                // 初始化接口

	fmt.Println("Name:" + p1.GetName())
	fmt.Println("Age:", p1.GetAge())
	s1.Age = 520
	fmt.Println("p1的Age:", p1.GetAge())
	fmt.Println("s1的Age:", s1.GetAge())
}

        上述代码最终输出结果如下:

Name:Sun
Age: 18
p1的Age: 18
s1的Age: 520

⭐️解释⭐️

  • 上述代码先定义了Student结构体,接着声明Person的接口,该接口集合中包括两种方法:用于获取姓名的GetName方法,以及获取年龄的GetAge方法。

  • 接着定义结构体变量s1以及接口变量p1,接口变量的结构其实存储了两种东西:动态类型动态值,当执行语句 var p1 Person = s1 时,接口变量p1的动态类型将变为Student,而其动态值将拷贝先前初始化的结构体变量s1当中的值

  •  由于是值拷贝,所以当s1当中的Age属性发生更改时,p1调用GetAge方法,仍然是先前未更改的s1的年龄

☀️注意:如果想动态值随着结构体变量事实更新,可将上述代码中的 var p1 Person = s1 改为var p1 Person = &s1 ,此时p1的动态类型为*Person,动态值为Person的指针。

⚡️小结:

        Go的接口变量其实存储了两个东西:

  1. 动态类型(是什么类型?比如 Dog 或 Cat

  2. 动态值(实际的数据,可能是指针或值的副本)

var s Speaker  // 接口变量
s = Dog{}      // s 存储了 (动态类型=Dog, 动态值=Dog的副本)
s = &Cat{}     // s 存储了 (动态类型=*Cat, 动态值=Cat的指针)

2.利用接口实现多态 🌻

package main
import (
	"fmt"
	"math"
)

// Shape 接口定义了一个计算面积的方法
type Shape interface {
	Area() float64
}

// Rectangle 结构体实现了 Shape 接口
type Rectangle struct {
	Width, Height float64
}

func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

// Circle 结构体实现了 Shape 接口
type Circle struct {
	Radius float64
}

func (c Circle) Area() float64 {
	return math.Pi * c.Radius * c.Radius
}

// DescribeShape 接受 Shape 接口类型的参数,输出图形的面积
func DescribeShape(s Shape) {
	fmt.Printf("Shape Area: %.2f\n", s.Area())
}

func main() {
	r := Rectangle{Width: 2, Height: 8}
	c := Circle{Radius: 5}

	// 计算不同图形的面积
	DescribeShape(r) // Shape Area: 16.00
	DescribeShape(c) // Shape Area: 78.54
}

上述代码通过接口,规定了Area方法用于计算不同图形的面积,接着定义了Rectangle三角形类以及Circle的圆形类,两个不同的类分别调用接口中的Area方法,Area方法依据传入的数据类型实现计算对应的面积,进而实现多态

3.空接口 🌻

空接口 interface{} 是 Go 的特殊接口,表示所有类型的超集。

  • 任意类型都实现了空接口。
  • 常用于需要存储任意类型数据的场景,如泛型容器、通用参数等。

⛅️示例代码:

package main

import "fmt"

func printValue(val interface{}) {         // 空接口作为函数参数,接收任意类型输入
        fmt.Printf("Value: %v, Type: %T\n", val, val)
}

func main() {
        printValue(42)         // int
        printValue("hello")    // string
        printValue(3.14)       // float64
        printValue([]int{1, 2}) // slice
}

        执行上述代码,最终输出结果如下:

Value: 42, Type: int
Value: hello, Type: string
Value: 3.14, Type: float64
Value: [1 2], Type: []int
  • 接口的零值是 nil。当接口变量的动态类型和动态值都为 nil 时,接口变量为 nil

4.小结🌻

接口的常见用法:

  1. 多态:不同类型实现同一接口,实现多态行为。
  2. 解耦:通过接口定义依赖关系,降低模块之间的耦合。
  3. 泛化:使用空接口 interface{} 表示任意类型。 

 


网站公告

今日签到

点亮在社区的每一天
去签到