专栏首页Golang语言社区厚土Go学习笔记 | 29. 接口

厚土Go学习笔记 | 29. 接口

在go语言中,接口类型是由一组方法定义的集合。

一个类型是否实现了一个接口,就看这个类型是否实现了接口中定义的所有方法。在go语言中,无需特别的指明?

定义一个接口

type Abser interface {
    Abs() float64
}

定义一个结构体

type Vertex struct {
    X, Y float64
}

定义两个方法,一个是结构体指针,一个是结构体。

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

func (v Vertex) Scale() float64 {
    return v.X + v.Y
}

声明一个接口变量

var a Abser

结构体也实例化一下

f := Vertex{3, 4}

指针也是 Vertex 结构体的指针,所以可以用 f 来实例化。

a = &f

下面你可以分别看一下 a 和 f 都能实现什么方法了。

fmt.Println(f.Abs())
fmt.Println(f.Scale())
fmt.Println(a.Abs())
fmt.Println(a.Scale())

仔细测试,你会发现 fmt.Println(a.Scale()) 是会报错的“a.Scale undefined (type Abser has no field or method Scale)”。是的,a 没有 Scale() 这个方法。

为什么呢?因为 func (v Vertex) Scale() float64 里的是 Vertex 而不是 *Vertex 。

如果你加上 * 符号,那么,a.Scale() 就可以实现了。

完整例子

package main

import (
    "fmt"
)

type Abser interface {
    Abs() float64
}
type Vertex struct {
    X, Y float64
}
func (v *Vertex) Abs() float64  {
    return v.X * v.X + v.Y * v.Y
}
func (v Vertex) Scale() float64 {
    return v.X + v.Y
}
func main() {
    var a Abser
    f := Vertex{3, 4}
    a = &f

    fmt.Println(f.Abs())
    fmt.Println(f.Scale())
    fmt.Println(a.Abs())
    //fmt.Println(a.Scale())
}

运行结果

25
7
25

结合上边的例子,我们可以发现,类型通过实现方法来实现接口,却不必要显示的声明。所以没有关键字 implements 。这是隐式接口。

隐式接口解耦了实现接口的包和定义接口的包,实现包和定义包“互不依赖”。

Stringers一个普遍存在的接口,在 fmt 中定义。

type Stringer interface {
    String() string
}

我们给它在包内依附一个结构体,定义一个 String() 方法。

type Cofox struct {
    name string
}

func (c *Cofox) String() string  {
    return "Joel " + c.name
}

为了区别原始的值,我们在 Strings() 内的返回值前加了一个字符串 Joel ,以作区别。

看完整代码

package main

import (
    "fmt"
)

type Stringer interface {
    String() string
}

type Cofox struct {
    name string
}

func (c *Cofox) String() string  {
    return "Joel " + c.name
}

func main() {
    var S Stringer
    c := Cofox{"Smith"}
    S = &c

    fmt.Println(S.String())
    fmt.Println(c.String())
    fmt.Println(c.name)
}

运行结果如下

Joel Smith
Joel Smith
Smith

接口和结构体都可以使用 String() 函数方法。

你可是试着把 String() 方法里的返回值写成

return fmt.Sprintf("full name is Joel %v", c.name)

运行自己看看结果有无不同。

再写一个例子,这次结构体多加一个字段,看看如何应用。

package main

import "fmt"

type Person struct {
    Name    string
    Age     int
}

func (p Person) String() string {
    return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func main() {
    a := Person{"Joel", 31}
    z := Person{"Smith", 45}
    fmt.Println(a, z)
}

运行结果

Joel (31 years) Smith (45 years)

本文分享自微信公众号 - Golang语言社区(Golangweb),作者:厚土火焰山

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-12-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 厚土Go学习笔记 | 29. 接口

    在go语言中,接口类型是由一组方法定义的集合。 一个类型是否实现了一个接口,就看这个类型是否实现了接口中定义的所有方法。在go语言中,无需特别的指明定义一个接口...

    李海彬
  • 厚土Go学习笔记 | 29. 接口

    在go语言中,接口类型是由一组方法定义的集合。 一个类型是否实现了一个接口,就看这个类型是否实现了接口中定义的所有方法。在go语言中,无需特别的指明? 定义一个...

    李海彬
  • 厚土Go学习笔记 | 28. go语言没有类 却可以在结构体或任意类型定义方法

    在go语言中没有类。可是,是有方法的。 给结构体定义方法,在对应的 func 和方法名之间,加上方法的接收者就可以了。 比如,我们定义了一个结构体 type V...

    李海彬
  • 厚土Go学习笔记 | 29. 接口

    在go语言中,接口类型是由一组方法定义的集合。 一个类型是否实现了一个接口,就看这个类型是否实现了接口中定义的所有方法。在go语言中,无需特别的指明定义一个接口...

    李海彬
  • 厚土Go学习笔记 | 29. 接口

    在go语言中,接口类型是由一组方法定义的集合。 一个类型是否实现了一个接口,就看这个类型是否实现了接口中定义的所有方法。在go语言中,无需特别的指明? 定义一个...

    李海彬
  • DDoS案例:chrome无法访问https问题排查

    我们经常会遇到https无法访问的问题,大部分时候根据浏览器的提示可以看出错误的原因,但是也有很多时候需要做进一步的排查。

    缪应厅
  • linux配置c++11编译环境

    下载对应版本repo文件, 放入/etc/yum.repos.d/(操作前请做好相应备份),以下为下载链接

    职场亮哥
  • Qt之任务栏系统托盘图标

    http://blog.csdn.net/qivan/article/details/7506306

    bear_fish
  • How to Update to gcc4.9.x on Centos7

    happy123.me
  • ubuntu 18.04 安装后基本配置以及常用软件安装

    $ sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

    foochane

扫码关注云+社区

领取腾讯云代金券