Go语言学习笔记(六)-方法和接口

方法

Go中没有类,但是可以为结构体定义方法,方法就是一类带有特殊的接受者参数的函数。方法接受者在它自己的参数列表内,位于func关键字和方法名之间。例如:

package main
import "fmt"
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())
}

你也可以为非结构体类型声明方法。但只能为在同一包内定义的类型的接收者声明方法, 而不能为其它包内定义的类型(包括 int 之类的内建类型)的接收者声明方法。也就是说接收者的定义与方法的声明必须在同一包内,且不能为内建类型声明方法。

指针接收者

在Go中可以为指针接收者定义方法,对于某个类型T的接收者的类型可以使用T文法(T不能是像int之类的指针)。指针接收者的方法可以修改接收者指向的值。由于方法经常需要修改它的接收者,指针接收者比值接收者更常用。
带指针参数的函数必须接受一个指针,而以指针为接收者的方法被调用时,接收者既能为值又能为指针。接受一个值作为参数的函数必须接受一个指定类型的值,而以值为接收者的方法被调用时,接收者既能为值又能为指针。
在开发中建议选择指针作为接收者,这样做有两个好处:

  • 方法可以直接修改接收者的值
  • 这样可以避免在每次调用方法时复制该值。若值的类型为大型结构体时,这样做会更加高效

接口

接口是由一组方法签名定义的集合,接口类型的值可以保存任何实现了接口方法的变量。类型通过实现了一个接口的所有方法来实现这个接口,而不需要专门的显示声明也就是"implements"关键字来声明。隐式接口从接口的实现中解耦了定义,这样接口的实现可以出现在任何包中,无需提前准备。
在内部,接口的值可以看做是包含值和具体类型的元组:

( value , type )

接口的值保存了一个具体底层类型的具体值,接口值调用方法时会调用具体底层类型的同名方法。在Go中即使接口值的底层值是nil,方法仍然会被nil的接收者调用。

package main

import "fmt"

type I interface {
    M()
}

type T struct {
    S string
}

func (t *T) M() {
    if t == nil {
        fmt.Println("<nil>")
        return
    }
    fmt.Println(t.S)
}

func main() {
    var i I

    var t *T
    i = t
    describe(i)
    i.M()

    i = &T{"hello"}
    describe(i)
    i.M()
}

func describe(i I) {
    fmt.Printf("(%v, %T)\n", i, i)
}

//输出结果
//(<nil>, *main.T)
//<nil>
//(&{hello}, *main.T)
//hello

而nil接口值不保存值也不保存具体类型。为nil接口调用方法会产生运行时错误,因为接口的元组内并未包含能够指明该调用哪个 具体 方法的类型。
指定了零个方法的接口被称为空接口,即:

interface{}

空接口可以保存任意类型的值,空接口一般是用来处理位置类型的值。

类型断言提供了访问接口值底层具体值的方法。

//断言i是T类型的值,并返回i的底层值返回给t
t := i.(T)

//断言i是V类型的值,若i是V类型的值ok的为true,v为i的底层值,否则ok为false,v为零值。
v,ok := i.(V)

以上就是接口断言的两种方式,第一种会触发warning提示,第二种则不会触发。因为第二种方式判断了i是否保存了T类型的值。

类型选择是一种按顺序从几个类型语言中选择分支的结构。与switch相似,不同的是类型选择中的case为类型。声明与类型断言相似,但是括号内由具体类型修改为type关键字。

package main

import "fmt"

func do(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("Twice %v is %v\n", v, v*2)
    case string:
        fmt.Printf("%q is %v bytes long\n", v, len(v))
    default:
        fmt.Printf("I don't know about type %T!\n", v)
    }
}

func main() {
    do(21)
    do("hello")
    do(true)
}

Stringer

fmt包中定义的Stringer是最普遍的接口之一。

type Stringer interface { String() string}

Stringer是一个可以用字符串描述自己的类型。fmt包(还有很多包)都通过此接口来打印值,Stringer的功能有点类似于java中的toString。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容