前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go——方法和接口

Go——方法和接口

作者头像
mumumu
发布2023-01-11 14:12:38
3430
发布2023-01-11 14:12:38
举报
文章被收录于专栏:blog1blog1

方法和接口

方法

  • Go没有类,但可以结构体定义方法
  • 方法就是一类带特殊的==接受者==的函数,接受者可以是命名类型结构体类型的一个值或一个指针
  • 方法接收者在它自己的参数列表内,位于func关键字和方法名之间
代码语言:javascript
复制
type Vertex struct{
    X,Y float64
}

func (v vertex)Abs()float64{
    return math.Sqrt(v.X*v.X+v.Y*v.Y)
}//Abs方法的接受者为v,类型为Vertex

func main (){
    v:=Vertex{3,4} 
}
fmt.Println(v.Abs())//输出为5
方法即函数
  • 方法只是带接受者的函数
  • 把上面的Abs函数写为正常函数为,功能不变
代码语言:javascript
复制
func Abs(v Vertex)float64{
    return math.Sqrt(v.X*v.X+v.Y*v.Y)
}
方法(续)
  • 也可以声明非结构体类型的声明方法
  • 接收者的类型定义和方法声明必须在同一包内;不能为内建类型声明方法
代码语言:javascript
复制
type MyFloat float64

func (f MyFloat)Abs()float64{//带 Abs 方法的数值类型 MyFloat。
    if(f<0)
    return float64(-f)
    else
    return float64(f)
}
指针接收者
  • 可以为指针接收者声明方法
  • 指针接收者的方法可以修改接收者指向的值
代码语言:javascript
复制
type Vertex struct {
    X,Y float64
}

func (v*Vertex)Abs(f float64){
    v.X=v.X*f
    v.Y=v.Y*f
}
指针与函数
  • 带指针参数的函数必须接受一个指针:func add(v *Vertex)int
  • 以指针为接收者的方法被调用时,接收者既能为又能为指针
选择 值or指针 为接收者

使用指针作为接收者的原因

  • 方法能够修改接收者指向的值
  • 避免每次调用方法时复制该值

接口

  • 接口类型是由一组方法签名定义的集合
  • 接口类型的变量可以保存任何实现了这些方法的值
代码语言:javascript
复制
type Abser interface{
    Abs()float64
}

func main (){
    var a Abser
    f:=MyFloat(-math.Sqrt2)
    v:=Vertex{3,4}
    
    a=f//a MyFloat实现了Abser
    a=&v//*Vertex实现了Abser
}
接口的隐式实现
  • 类型通过实现一个接口的所有方法来实现该接口
  • 隐式接口从接口的实现中解耦了定义,这样接口的实现可以出现在任何包中
  • 因为无需在每一个实现上增加新的接口名称,可以同时也鼓励了明确的接口定义
代码语言:javascript
复制
type I interface{
    M()
}

type T struct {
    string S
}
// 此方法表示类型 T 实现了接口 I,但我们无需显式声明此事。
func (t T)M(){
        fmt.Piintln(t.S)
    }

func main (){
    var i I=T{"hello"}
    i.M()
}
接口值
  • 接口值也是值,可以像其他值一样传递
  • 可以用作函数的参数或返回值
  • 在内部,接口值可以看做包含值和具体类型的元组
  • 接口值调用方法时会执行其底层类型的同名方法
代码语言:javascript
复制
type I interface{//定义接口类型
    M()
}

type T struct{
    string S
}

func (t*T)M(){//方法M
    fmt.Printf(t.S)    
}

type F float64

func(f F)M(){//f作为方法M()的接收者
    fmt.Println(f)
}

func main (){
    var i I//接口类型变量i
    i=&T{"hello"}
    describe(i)//接口值作为函数的参数
    i.M()//接口值调用方法,与此同时,会执行其底层类型的同名方法
    
    func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}

}
底层值为nil的接口值
  • 即使接口内的具体值为nil,方法仍会被nil接收者调用
代码语言:javascript
复制
func (t*T)M(){
    if(t==nil){
        fmt.Println("<nil>")
        return 
    }
    fmt.Println(t.S)
}
nil接口值
  • nil接口值既不保存值也不保存具体类型
  • nil接口调用方法会发生错误,因为接口的元组没有包含指明调用哪个具体的方法的类型
空接口
  • 指定了零个方法的接口值为空接口
代码语言:javascript
复制
interface{}
  • 空接口可以保存任何类型的值(因为每个类型都至少实现了零个方法)
  • 空接口用来处理未知类型的值
类型断言
  • 类型断言提供访问接口值底层具体值的方式
代码语言:javascript
复制
t:=i.(T)
  • 为了判断一个接口值是否保存了一个特定类型,类型断言可返回两个值:底层值报告断言是否成功的布尔值
代码语言:javascript
复制
t,ok:=i(T)
代码语言:javascript
复制
func main (){
    var i interface{}="hello"
    
    s:=i.(string)
    
    s,ok:=i.(string)
}
类型选择
  • 类型选择是一种按顺序从几个类型断言中选择分支的结构
  • 类型选择与一般的switch类似,只不过case是类型而不是值
代码语言:javascript
复制
switch v:=i.(type){
    case T://V的类型为T
    case S:
    default:
}
  • 类型选择中的声明与类型断言的i.(T)相同,只是具体类型T换为了type
Stringer
  • fmt包中定义的Stringer是最普遍的接口之一
代码语言:javascript
复制
type Stringer interface{
    String()string
}
  • Stirng可以用字符串描述自己的类型
代码语言:javascript
复制
type person struct {
    Name String 
    Age int 
}

func (p person) String () stirng{
    return fmt.Sprintf("%v,(%v years)",P.Name,P.Age)
}

func main (){
    a:=person{"bob",32}
    b:=person{"tom",12}
    fmt.Println(a,b)
}

错误

  • error表示错误状态
  • 和fmt.Sprintf相似,error只是一个内建接口
代码语言:javascript
复制
type error interface{
    Error()string
}
  • 通常函数会返回一个error值,调用它的代码应该判断这个错误是否等于nil来错误处理
  • error为nil表示成功,非nil的error表示失败

Reader

  • io包指定了io.reader接口,表示从数据流的末尾进行读取
  • io.reader的一个接口方法
代码语言:javascript
复制
func (T)Read(b[]byte)(n int err error)
  • read用数据填充给定的字节切片并返回填充的字节数和错误值。在遇到数据流结尾时,会返回一个io.EOF错误

图像

  • image包定义了image接口
代码语言:javascript
复制
package image

type Image interface{
    ColorModel()color.Model
    Bounds()Rectangle
    At(x,y int)color.Color
}
代码语言:javascript
复制
import (
	"fmt"
	"image"
)

func main() {
	m := image.NewRGBA(image.Rect(0, 0, 100, 100))
	fmt.Println(m.Bounds())
	fmt.Println(m.At(0, 0).RGBA())
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 方法和接口
    • 方法
      • 接口
        • 错误
          • Reader
            • 图像
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档