Go语言入门 (Day 4) 方法和接口

本文深入探讨Go语言的方法和接口。介绍了如何为结构体和非结构体类型定义方法,重点讲解了指针接收者、方法与指针重定向的概念。接着详细阐述了接口的特性,包括隐式实现、接口值、类型断言和类型选择,并通过具体示例展示了如何使用接口。文章还涉及了常见的Stringer、错误和Reader接口的实现和应用。
摘要由CSDN通过智能技术生成

Go 方法和接口

方法

Go 没有类。不过你可以为结构体类型定义方法。

方法就是一类带特殊的 接收者 参数的函数。

方法接收者在它自己的参数列表内,位于 func 关键字和方法名之间。

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
   
	X, Y float64
}

func (v Vertex) Abs() float64 {
   
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
   
	v := Vertex{
   3, 4}
	fmt.Println(v.Abs())
}

输出:

5

在此例中,Abs 方法拥有一个名为 v,类型为 Vertex 的接收者。

方法即函数

记住:方法只是个带接收者参数的函数。

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
   
	X, Y float64
}

func Abs(v Vertex) float64 {
   
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
   
	v := Vertex{
   3, 4}
	fmt.Println(Abs(v))
}

输出:

5

这个例子中 Abs 的写法就是个正常的函数,功能并没有什么变化。

方法(续)

你也可以为非结构体类型声明方法。

package main

import (
	"fmt"
	"math"
)

type MyFloat float64

func (f MyFloat) Abs() MyFloat {
   
	if f < 0 {
   
		return -f
	}
	return f
}

func main() {
   
	f := MyFloat(-math.Sqrt2)
	fmt.Println(f.Abs())
}

输出:

1.4142135623730951

在此例中,我们看到了一个带 Abs 方法的数值类型 MyFloat

你只能为在同一包内定义的类型的接收者声明方法,而不能为其它包内定义的类型(包括 int 之类的内建类型)的接收者声明方法。

(译注:就是接收者的类型定义和方法声明必须在同一包内;不能为其他包中声明的类型声明方法。)

指针接收者

你可以为指针接收者声明方法。

这意味着对于某类型 T,接收者的类型可以用 *T 的文法。(此外,T 不能是像 *int这样的指针。)

例如,这里为 *Vertex 定义了 Scale 方法。

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
   
	X, Y float64
}

func (v Vertex) Abs() float64 {
   
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex) Scale(f float64) {
   
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
   
	v := Vertex{
   3, 4}
	v.Scale(10)
	fmt.Println(v.Abs())
}

输出:

50

指针接收者的方法可以修改接收者指向的值(就像 Scale 在这做的)。由于方法经常需要修改它的接收者,指针接收者比值接收者更常用。

试着移除第 16 行 Scale 函数声明中的 *,观察此程序的行为如何变化。

若使用值接收者,那么 Scale 方法会对原始 Vertex 值的副本进行操作。(对于函数的其它参数也是如此。)Scale 方法必须用指针接受者来更改 main 函数中声明的 Vertex 的值。

指针与函数

现在我们要把 AbsScale 方法重写为函数。

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
   
	X, Y float64
}

func Abs(v Vertex) float64 {
   
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func Scale(v *Vertex, f float64) {
   
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
   
	v := Vertex{
   3, 4}
	Scale(&v, 10)
	fmt.Println(Abs(v))
}

输出:

50

同样,我们先试着移除掉第 16 行 Scale 函数声明中的 *。尝试编译,会得到 ./src.go:23:8: cannot use &v (type *Vertex) as type Vertex in argument to Scale,按照提示,我们再把 main 函数中 Scale 函数的调用里的 &v 改成 v,再尝试编译,通过了,输出结果为 5

方法与指针重定向
package main

import "fmt"

type Vertex struct {
   
	X, Y float64
}

func (v *Vertex) Scale(f float64) {
   
	v.X *= f
	v.Y *= f
}

func ScaleFunc(v *Vertex, f float64) {
   
	v.X *= f
	v.Y *= f
}

func main() {
   
	v := Vertex{
   3, 4}
	v.Scale(2)
	ScaleFunc(&v, 10)

	p := &Vertex{
   4, 3}
	p.Scale(3)
	ScaleFunc(p, 8)

	fmt.Println(v, p)
}

输出&#

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值