详解Golang语言中的interface

interface是一组method签名的组合,interface可以被任意对象实现,一个对象也可以实现多个interface。任意类型都实现了空interface(也就是包含0个method的interface),空interface可以存储任意类型的值。interface定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。

go version go1.12

package main

import (
  "fmt"
)

// 定义struct
type Human struct {
  name string
  age  int
  phone string
}
type Student struct {
  Human // 匿名字段
  school string
  loan  float32
}
type Employee struct {
  Human  // 匿名字段
  company string
  money  float32
}

// Human对象实现SayHi()方法
func (h Human) SayHi() {
  fmt.Printf("Hi, I am %s, you can call me on %s\n", h.name, h.phone)
}

// Human对象实现Sing()方法
func (h Human) Sing(lyrics string) {
  fmt.Println("La la la...", lyrics)
}

// Human对象实现Guzzle()方法
func (h Human) Guzzle(beerStein string) {
  fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}

// Employee对象重写SayHi()方法
func (e Employee) SayHi() {
  fmt.Printf("Hi I am %s, I work at %s. Call me on %s\n", e.name, e.company, e.phone)
}

// Student对象实现BorrowMoney()方法
func (s Student) BorrowMoney(amount float32) {
  s.loan += amount
}

// Employee对象实现SpendSalary()方法
func (e Employee) SpendSalary(amount float32) {
  e.money -= amount
}

// 定义interface,interface是一组method签名的组合
// interface可以被任意对象实现,一个对象也可以实现多个interface
// 任意类型都实现了空interface(也就是包含0个method的interface)
// 空interface可以存储任意类型的值
// interface Men的3个method被Human,Student,Employee实现,也就是这3个对象都实现了interface Men。即:
// interface定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。
type Men interface {
  SayHi()
  Sing(lyrice string)
  Guzzle(beerStein string)
}

// interface YoungChap的BorrowMoney() method只被Student对象实现,也就是只有Student实现了YoungChap
type YoungChap interface {
  SayHi()
  Sing(song string)
  BorrowMoney(amount float32)
}

// interface ElderlyGent的SpendSalary() method只被Employee对象实现,也就是只有Employee实现了ElderlyGent
type ElderlyGent interface {
  SayHi()
  Sing(song string)
  SpendSalary(amount float32)
}

func main() {
  // 定义Student类型的变量
  lucy := Student{Human{"lucy", 19, "10086"}, "tsinghua", 100.00}
  lily := Student{Human{"lily", 19, "10086"}, "tsinghua", 100.00}
  liming := Student{Human{"liming", 19, "10086"}, "tsinghua", 100.00}
  // 定义Employee类型的变量
  tom := Employee{Human{"tom", 29, "10000"}, "Google", 200.00}
  // 定义Men类型的变量i
  var i Men
  // i存储Student
  i = lucy
  fmt.Println("This is lucy, a student:")
  i.SayHi()
  i.Sing("Happy Birthday")
  i.Guzzle("Ha ha ha...")

  // i存储Employee
  i = tom
  fmt.Println("This is tom, an Employee:")
  i.SayHi()

  // 定义slice Men,包含Men类型元素的切片,这个slice可以被赋予实现了Men接口的任意结构的对象
  fmt.Println("Let's use a slice of Men and see what happens:")
  x := make([]Men, 3)
  // 三个不同类型(不同Method)的元素,实现了同一个interface(Men)
  x[0], x[1], x[2] = lucy, lily, liming
  for _, value := range x {
    value.SayHi()
  }
}

函数参数

interface接口还可以作为函数参数,因为interface的变量可以持有任意实现该interface类型的对象,我们可以通过定义interface参数,让函数接受各种类型的参数。 判断interface变量存储的元素的类型,目前常用的有两种方法:Comma-ok断言和switch测试。

go version go1.12

/**
 * interface接口作为函数参数
 * 判断interface变量存储的元素的类型
 */
package main

import (
  "fmt"
  "strconv"
)

// 定义Human对象
type Human struct {
  name string
  age  int
  phone string
}

// 定义空接口
type Element interface{}

// 定义切片
type List []Element

// 定义Person对象
type Person struct {
  name string
  age int
}

// 通过定义interface参数,让函数接受各种类型的参数
// 通过这个Method(方法),Human对象实现了fmt.Stringer接口
// Stringer接口是fmt.Println()的参数,最终使得Human对象可以作为fmt.Println的参数被调用
func (h Human) String() string {
  return "<" + h.name + " - " + strconv.Itoa(h.age) + " years - phone: " + h.phone + ">"
}

// 通过定义interface参数,让函数接受各种类型的参数
// 通过这个Method(方法),Person对象实现了fmt.Stringer接口
// Stringer接口是fmt.Println()的参数,最终使得Person对象可以作为fmt.Println的参数被调用
func (p Person) String() string {
  return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}

func main() {
  // interface作为函数的参数传递
  Lucy := Human{"Lucy", 29, "10086"}
  fmt.Println("This human is:", Lucy)

  list := make(List, 3)
  list[0] = 100
  list[1] = "Hello Golang!"
  list[2] = Person{"Lily", 19}

  // Comma-ok断言
  for index, element := range list {
    // 判断变量的类型 格式:value, ok = element(T)
    // value是interface变量的值,ok是bool类型,element是interface的变量,T是断言的interface变量的类型
    if value, ok := element.(int); ok {
      fmt.Printf("list[%d] is an int and it's value is %d\n", index, value)
    } else if value, ok := element.(string); ok {
      fmt.Printf("list[%d] is a string and it's value is %s\n", index, value)
    } else if value, ok := element.(Person); ok {
      fmt.Printf("list[%d] is a Person and it's value is %s\n", index, value)
    } else {
      fmt.Printf("list[%d] is a different type\n", index)
    }
  }

  // switch
  for index, element := range list {
    // 注意:element.(type)语法不能在switch外的任何逻辑中使用
    switch value := element.(type) {
    case int:
      fmt.Printf("list[%d] is an int, it's value is %d\n", index, value)
    case string:
      fmt.Printf("list[%d] is a string, it's value is %s\n", index, value)
    case Person:
      fmt.Printf("list[%d] is a Person, it's value is %s\n", index, value)
    default:
      fmt.Printf("list[%d] is a differernt type", index)
    }
  }
}

以上就是详解Golang语言中的interface的详细内容,更多关于Golang语言中的interface的资料请关注我们其它相关文章!

(0)

相关推荐

  • golang基础之Interface接口的使用

    接口是一个或多个方法签名名的集合,定义方式如下 type Interface_Name interface { method_a() string method_b() int .... } 只要某个类型拥有该接口的所有方法签名,就算实现该接口,无需显示声明实现了那个接口,这称为structural Typing package main import "fmt" type USB interface { //定义一个接口:方法的集合 Name() string //Name方法,返回

  • golang struct 实现 interface的方法

    golang中,一般strcut包含 interface类型后,struct类型都需要实现 interface导出的接口,从而成为相应的 interface接口类. 实际上,struct包含interface之后,并不需要实现interface的接口,也能成为 interface接口类. 代码如下: type newEr interface { New() } type testInterface interface { newEr Done() <-chan struct{} } type k

  • golang 实现interface{}转其他类型操作

    golang中的string是可以转换为byte数组或者rune数组 但是其实byte对应的类型是uint8,而rune对应的数据类型就是int32 所以string可以转换为四种类型 //interface转其他类型----返回值是interface,直接赋值是无法转化的 //interface 转string var a interface{} var str5 string a = "3432423" str5 = a.(string) fmt.Println(str5) //i

  • golang中struct和interface的基础使用教程

    前言 本文主要给大家介绍了关于golang中struct和interface的相关内容,是属于golang的基本知识,下面话不多说了,来一起看看详细的介绍吧. struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套:go中的struct类型理解为类,可以定义方法,和函数定义有些许区别:struct类型是值类型. struct定义 type User struct { Name string Age int32 mess string } var user User

  • golang语言如何将interface转为int, string,slice,struct等类型

    在golang中,interface{}允许接纳任意值,int,string,struct,slice等,因此我可以很简单的将值传递到interface{},例如: package main import ( "fmt" ) type User struct{ Name string } func main() { any := User{ Name: "fidding", } test(any) any2 := "fidding" test(a

  • golang中interface接口的深度解析

    一 接口介绍 如果说gorountine和channel是支撑起Go语言的并发模型的基石,让Go语言在如今集群化与多核化的时代成为一道亮丽的风景,那么接口是Go语言整个类型系列的基石,让Go语言在基础编程哲学的探索上达到前所未有的高度.Go语言在编程哲学上是变革派,而不是改良派.这不是因为Go语言有gorountine和channel,而更重要的是因为Go语言的类型系统,更是因为Go语言的接口.Go语言的编程哲学因为有接口而趋于完美.C++,Java 使用"侵入式"接口,主要表现在实现

  • 详解Golang语言中的interface

    interface是一组method签名的组合,interface可以被任意对象实现,一个对象也可以实现多个interface.任意类型都实现了空interface(也就是包含0个method的interface),空interface可以存储任意类型的值.interface定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口. go version go1.12 package main import ( "fmt" ) // 定义struct type Hu

  • 详解go语言中sort如何排序

    目录 sort包源码解读 前言 如何使用 基本数据类型切片的排序 自定义Less排序比较器 自定义数据结构的排序 分析下源码 不稳定排序 稳定排序 查找 Interface 总结 参考 sort 包源码解读 前言 我们的代码业务中很多地方需要我们自己进行排序操作,go 标准库中是提供了 sort 包是实现排序功能的,这里来看下生产级别的排序功能是如何实现的. go version go1.16.13 darwin/amd64 如何使用 先来看下 sort 提供的主要功能 对基本数据类型切片的排序

  • 详解Go语言中Goroutine退出机制的原理及使用

    目录 退出方式 进程/main函数退出 通过channel退出 通过context退出 通过Panic退出 等待自己退出 阻止goroutine退出的方法 通过sync.WaitGroup 通过channel 封装 总结 goroutine是Go语言提供的语言级别的轻量级线程,在我们需要使用并发时,我们只需要通过 go 关键字来开启 goroutine 即可.作为Go语言中的最大特色之一,goroutine在日常的工作学习中被大量使用着,但是对于它的调度处理,尤其是goroutine的退出时机和

  • 详解Go语言中for range的"坑"

    前言 Go 中的for range组合可以和方便的实现对一个数组或切片进行遍历,但是在某些情况下使用for range时很可能就会被"坑",下面用一段代码来模拟下: func main() { arr1 := []int{1, 2, 3} arr2 := make([]*int, len(arr1)) for i, v := range arr1 { arr2[i] = &v } for _, v := range arr2 { fmt.Println(*v) } } 代码解析

  • 详解go语言中type关键词的几种使用

    type是go语法里的重要而且常用的关键字,type绝不只是对应于C/C++中的typedef.搞清楚type的使用,就容易理解go语言中的核心概念struct.interface.函数等的使用.以下我用例子代码总结描述,请特别留意代码中的注释. 1.定义结构体 //结构体定义 type person struct { name string //注意后面不能有逗号 age int } func main() { //结构体初始化 p := person{ name: "taozs",

  • 详解C语言中return与exit的区别

    详解C语言中return与exit的区别 1,exit用于在程序运行的过程中随时结束程序,exit的参数是返回给OS的.main函数结束时也会隐式地调用exit函数.exit函数运行时首先会执行由atexit()函数登记的函数,然后会做一些自身的清理工作,同时刷新所有输出流.关闭所有打开的流并且关闭通过标准I/O函数tmpfile()创建的临时文件.exit是结束一个进程,它将删除进程使用的内存空间,同时把错误信息返回父进程,而return是返回函数值并退出函数 2,return是语言级别的,它

  • 详解 Go 语言中 Map 类型和 Slice 类型的传递

    Map 类型 先看例子 m1: func main() { m := make(map[int]int) mdMap(m) fmt.Println(m) } func mdMap(m map[int]int) { m[1] = 100 m[2] = 200 } 结果是 map[2:200 1:100] 我们再修改如下 m2: func main() { var m map[int]int mdMap(m) fmt.Println(m) } func mdMap(m map[int]int) {

  • 详解C语言中Char型指针数组与字符数组的区别

    详解C语言中Char型指针数组与字符数组的区别 1.char 类型的指针数组:每个元素都指向一个字符串,指向可以改变 char *name[3] = { "abc", "def", "gbk" }; for(int i = 0 ; i < strlen(name); i ++){ printf("%s\n", *(name+i)); //printf("%s\n", name[i]); } //指向改

  • 详解R语言中的PCA分析与可视化

    1. 常用术语 (1)标准化(Scale) 如果不对数据进行scale处理,本身数值大的基因对主成分的贡献会大.如果关注的是变量的相对大小对样品分类的贡献,则应SCALE,以防数值高的变量导入的大方差引入的偏见.但是定标(scale)可能会有一些负面效果,因为定标后变量之间的权重就是变得相同.如果我们的变量中有噪音的话,我们就在无形中把噪音和信息的权重变得相同,但PCA本身无法区分信号和噪音.在这样的情形下,我们就不必做定标. (2)特征值 (eigen value) 特征值与特征向量均为矩阵分

  • 详解C++语言中std::array的神奇用法

    概述 std::array是在C++11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能.也正因此,使得std::array有很多与其他容器不同的特殊之处,比如:std::array的元素是直接存放在实例内部,而不是在堆上分配空间:std::array的大小必须在编译期确定:std::array的构造函数.析构函数和赋值操作符都是编译器隐式声明的--这让很多用惯了std::vector这类容器的程序员不习惯,觉得std::array不好用.但实际上,std::array的威力

随机推荐