Golang 06 接口与反射

总篇:33

编辑于 2025/6/23 20:00

截稿于: 2025/6/23 23:00

《Go 入门指南》 | Go 技术论坛

第十一章

接口

和Java的接口差别不大,Go没有类和继承的概念,接口成了方法的核心。

声明接口

一个接口的方法可以被多个结构体实现,同时结构体必须实现接口内所有方法,否则编译报错。

package interfaces

// Shape 定义了一个接口,包含一个 Area 方法
type Shape interface {
	Area() float64
}

// Circle 表示一个圆
type Circle struct {
	Radius float64
}

// Rectangle 表示一个矩形
type Rectangle struct {
	Width  float64
	Height float64
}

// Circle 的 Area 方法
func (c Circle) Area() float64 {
	return 3.14159 * c.Radius * c.Radius
}

// Rectangle 的 Area 方法
func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

package main

import (
	"day06/interfaces"
	"fmt"
)

func main() {
	// 创建一个 Circle 实例
	circle := interfaces.Circle{Radius: 5}
	// 创建一个 Rectangle 实例
	rectangle := interfaces.Rectangle{Width: 4, Height: 6}
	// 将 Circle 和 Rectangle 赋值给 Shape 类型的变量
	var shape interfaces.Shape
	shape = circle
	fmt.Println("Circle area:", shape.Area()) // 输出: Circle area: 78.53975
	shape = rectangle
	fmt.Println("Rectangle area:", shape.Area()) // 输出: Rectangle area: 24
}

嵌套接口

一个接口可以包含一个或多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。

在File接口内就有应用:

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type Lock interface {
    Lock()
    Unlock()
}

type File interface {
    ReadWrite // 展开有Read,Write方法
    Lock // 展开Lock() Unlock() 方法
    Close() //File自定义的方法
}

类型断言:检测和转换接口变量的类型

package main

import (
	"day06/interfaces"
	"fmt"
)

func main() {
	//interface1()
	interface2()
}

func interface1() {
	// 创建一个 Circle 实例
	circle := interfaces.Circle{Radius: 5}
	// 创建一个 Rectangle 实例
	rectangle := interfaces.Rectangle{Width: 4, Height: 6}
	// 将 Circle 和 Rectangle 赋值给 Shape 类型的变量
	var shape interfaces.Shape
	shape = circle
	fmt.Println("Circle area:", shape.Area()) // 输出: Circle area: 78.53975
	shape = rectangle
	fmt.Println("Rectangle area:", shape.Area()) // 输出: Rectangle area: 24
}

func interface2() {
	circle := interfaces.Circle{Radius: 5}
	circle.Radius = 5
	var shape interfaces.Shape
	shape = circle
	if t, ok := shape.(*interfaces.Circle); ok {
		fmt.Println("Circle area:", t.Area())
	} else { //circle是字面量初始化,不是指针,所以会走到这里
		fmt.Println("Not a circle pointer")
	}
}

使用swtich-case 语句:

package main

import (
	"day06/interfaces"
	"fmt"
)

func main() {
	interface2()
}

func interface2() {
	circle := interfaces.Circle{Radius: 5}
	circle.Radius = 5
	var shape interfaces.Shape
	shape = circle
	switch t := shape.(type) {
	case interfaces.Circle:
		fmt.Printf("Type Square %T with value %v\n", t, t)
	case interfaces.Rectangle:
		fmt.Printf("Type Circle %T with value %v\n", t, t)
	case nil:
		fmt.Printf("nil value: nothing to check?\n")
	default:
		fmt.Printf("Unexpected type %T\n", t)
	}
}

Go 语言规范定义了接口方法集的调用规则:

  • 类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集
  • 类型 T 的可调用方法集包含接受者为 T 的所有方法
  • 类型 T 的可调用方法集不包含接受者为 *T 的方法

即指针优先级最高,感觉就用值接收者就足够了。

以下举例:

package main

import (
    "fmt"
    "math"
)

// Shape 定义了一个接口,包含一个 Area 方法
type Shape interface {
    Area() float64
}

// Circle 表示一个圆
type Circle struct {
    Radius float64
}

// Rectangle 表示一个矩形
type Rectangle struct {
    Width  float64
    Height float64
}

// Circle 的 Area 方法(指针接收者)
func (c *Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

// Rectangle 的 Area 方法(值接收者)
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

指针:

func main() {
    // 创建一个值类型的 Rectangle 实例
    rectangle := Rectangle{Width: 4, Height: 6}

    // 将 rectangle 赋值给 Shape 接口
    var shape Shape = rectangle

    // 调用接口方法
    fmt.Println("Rectangle area:", shape.Area()) // 输出: Rectangle area: 24
}

值:

func main() {
    // 创建一个值类型的 Rectangle 实例
    rectangle := Rectangle{Width: 4, Height: 6}

    // 调用值接收者方法
    fmt.Println("Rectangle area:", rectangle.Area()) // 输出: Rectangle area: 24

    // 不能调用指针接收者方法
    // rectangle.SetWidth(10) // 编译错误:cannot call pointer method on rectangle
}

空接口

空接口或者最小接口 不包含任何方法,它对实现不做任何要求,可以被赋予任何值:

type Any interface {}
package main

import (
	"day06/interfaces"
	"fmt"
)

func main() {
	interface3()
}

func interface3() {
	var any interfaces.Any
	any = 3
	fmt.Println(any)
	any = "hello"
	fmt.Println(any)
	cirlce := interfaces.Circle{Radius: 5}
	any = cirlce
	fmt.Println(any)
}

使用空接口实现仍以类型的切片或数组,感觉很鸡肋:

package main

import (
	"day06/interfaces"
	"fmt"
)

func main() {
	interface4()
}

func interface4() {
	// 创建一个包含不同类型值的切片
	var mixed []interface{}
	mixed = append(mixed, 42)             // int
	mixed = append(mixed, "hello")        // string
	mixed = append(mixed, 3.14)           // float64
	mixed = append(mixed, true)           // bool
	mixed = append(mixed, []int{1, 2, 3}) // []int

	// 遍历切片并打印每个元素
	for _, value := range mixed {
		fmt.Printf("Type: %T, Value: %v\n", value, value)
	}
}

反射包

reflect.TypeOf(x):获取x的类型,reflect.ValueOf(x):获取x的值

package main

import (
	"day06/interfaces"
	"fmt"
	"reflect"
)

func main() {
	reflect1()
}

func reflect1() {
	var x float64 = 3.4
	fmt.Println("type:", reflect.TypeOf(x))
	v := reflect.ValueOf(x)
	fmt.Println("value:", v)
	fmt.Println("type:", v.Type())
	fmt.Println("kind:", v.Kind())
	fmt.Println("value:", v.Float())
	fmt.Println(v.Interface())
	fmt.Printf("value is %5.2e\n", v.Interface())
	y := v.Interface().(float64)
	fmt.Println(y)
}

posted on 2025-07-14 00:27  依只  阅读(11)  评论(0)    收藏  举报

导航