一、概念
1、 面向对象语言中,接口用于定义对象的行为。接口只指定对象应该做什么,实现这种行为的方法(实现细节)是由对象来决定。
2、 在Go语言中,接口是一组方法签名。

  • •接口只指定了类型应该具有的方法,类型决定了如何实现这些方法。
  • •当某个类型为接口中的所有方法提供了具体的实现细节时,这个类型就被称为实现了该接口。
  • •接口定义了一组方法,如果某个对象实现了该接口的所有方法,则此对象就实现了该接口。

3、 Go语言的类型都是隐式实现接口的。任何定义了接口中所有方法的类型都被称为隐式地实现了该接口。

二、接口的使用

go没有 implements, extends 关键字,其实这种编程语言叫做duck typing编程语言。

  1. package main
  2.  
  3. import "fmt"
  4. import "base"
  5.  
  6. //定义接口
  7. type Phone interface {
  8. call()
  9. }
  10.  
  11. type AndroidPhone struct {
  12. }
  13.  
  14. type IPhone struct {
  15. }
  16.  
  17. func (a AndroidPhone) call() {
  18. fmt.Println("我是安卓手机,可以打电话了")
  19. }
  20.  
  21. func (i IPhone) call() {
  22. fmt.Println("我是苹果手机,可以打电话了")
  23. }
  24.  
  25. func main() {
  26. // 定义接口类型的变量
  27. var phone Phone
  28. //phone = new(AndroidPhone)
  29. phone = AndroidPhone{}
  30. fmt.Printf("%T , %v , %p \n" , phone , phone , &phone)
  31. phone.call()
  32.  
  33. //phone = new(IPhone)
  34. phone = IPhone{}
  35. fmt.Printf("%T , %v , %p \n" , phone , phone , &phone)
  36. phone.call()
  37. }

 动态类型与静态类型语言

  • •动态类型的好处很多,Python代码写起来很快。但是缺陷也是显而易见的:错误往往要在运行时才能被发现。
  • •相反,静态类型语言往往在编译时就是发现这类错误:如果某个变量的类型没有显式声明实现了某个接口,那么,这个变量就不能用在要求一个实现了这个接口的地方。

 Go类型系统采取了折中的办法:
•之所以说这是一种折中的办法,原因如下:

  • 〇第一,结构体类型T不需要显式地声明它实现了接口 I。只要类型T实现了接口1规定的所有方法,它就自动地实现了接口 I。这样就像动态语言一样省了很多代码,少了许多限制。
  • 〇第二,将结构体类型的变量显式或者隐式地转换为接口 I类型的变量i。这样就可以和其它静态类型语言一样,在编译时检查参数的合法性。

三、多态

•事物的多种形态

  • • Go中的多态性是在接口的帮助下实现的。定义接口类型,仓U建实现该接口的结构体对象。
  • •定义接口类型的对象,可以保存实现该接口的任何类型的值。Go语言接口变量的这个特性实现了 Go语言中的多态性。
  • •接口类型的对象,不能访问其实现类中的属性字段。
  1. package main
  2.  
  3. import "fmt"
  4. import "base"
  5.  
  6. type Income interface {
  7. calculate() float64 //计算收入总额
  8. source() string //用来说明收入来源
  9. }
  10.  
  11. //固定账单项目
  12. type FixedBilling struct {
  13. projectName string //工程项目
  14. biddedAmount float64 //项目招标总额
  15. }
  16.  
  17. //定时生产项目(定时和材料项目)
  18. type TimeAndMaterial struct {
  19. projectName string
  20. workHours float64 //工作时长
  21. hourlyRate float64 //每小时工资率
  22. }
  23.  
  24. //固定收入项目
  25. func (f FixedBilling) calculate() float64 {
  26. return f.biddedAmount
  27. }
  28.  
  29. func (f FixedBilling) source() string {
  30. return f.projectName
  31. }
  32.  
  33. //定时收入项目
  34. func (t TimeAndMaterial) calculate() float64 {
  35. return t.workHours * t.hourlyRate
  36. }
  37.  
  38. func (t TimeAndMaterial) source() string {
  39. return t.projectName
  40. }
  41.  
  42. //通过广告点击获得收入
  43. type Advertisement struct {
  44. adName string
  45. clickCount int
  46. incomePerclick float64
  47. }
  48.  
  49. func (a Advertisement) calculate() float64 {
  50. return float64(a.clickCount) * a.incomePerclick
  51. }
  52.  
  53. func (a Advertisement) source() string {
  54. return a.adName
  55. }
  56.  
  57. func main() {
  58. p1 := FixedBilling{"项目1", }
  59. p2 := FixedBilling{"项目2", }
  60. p3 := TimeAndMaterial{"项目3", , }
  61. p4 := TimeAndMaterial{"项目4", , }
  62. p5 := Advertisement{"广告1", , 0.1}
  63. p6 := Advertisement{"广告2", , 0.05}
  64.  
  65. ic := []Income{p1, p2, p3, p4, p5, p6}
  66. fmt.Println("total=",calculateNetIncome(ic))
  67. }
  68.  
  69. //计算净收入
  70. func calculateNetIncome(ic []Income) float64 {
  71. netincome := 0.0
  72. for _, income := range ic {
  73. fmt.Printf("收入来源:%s ,收入金额:%.2f \n", income.source(), income.calculate())
  74. netincome += income.calculate()
  75. }
  76. return netincome
  77. }

四、空接口

•空接口 :该接口中没有任何的方法。任意类型都可以实现该接口。
•空interface这样定义:interface{},也就是包含0个method的interface。
•用空接口表示任意数据类型。类似于java中的object。
•空接口常用于以下情形:
〇 1、println的参数就是空接口
〇 2、定义一个map: key是string,value是任意数据类型
〇 3、定义一个切片,其中存储任意类型的数据

  1. package main
  2.  
  3. import (
  4. "fmt"
  5. )
  6.  
  7. type A interface {
  8. }
  9.  
  10. type Cat struct {
  11. name string
  12. age int
  13. }
  14.  
  15. type Person struct {
  16. name string
  17. sex string
  18. }
  19.  
  20. func main() {
  21. var a1 A = Cat{"Mimi", }
  22. var a2 A = Person{"Steven", "男"}
  23. var a3 A = "Learn golang with me!"
  24. var a4 A =
  25. var a5 A = 3.14
  26.  
  27. showInfo(a1)
  28. showInfo(a2)
  29. showInfo(a3)
  30. showInfo(a4)
  31. showInfo(a5)
  32. fmt.Println("------------------")
  33.  
  34. //1、fmt.println参数就是空接口
  35. fmt.Println("println的参数就是空接口,可以是任何数据类型", , 3.14, Cat{"旺旺", })
  36.  
  37. //2、定义map。value是任何数据类型
  38. map1 := make(map[string]interface{})
  39. map1["name"] = "Daniel"
  40. map1["age"] =
  41. map1["height"] = 1.71
  42. fmt.Println(map1)
  43. fmt.Println("------------------")
  44.  
  45. // 3、定义一个切片,其中存储任意数据类型
  46. slice1 := make([]interface{}, , )
  47. slice1 = append(slice1, a1, a2, a3, a4, a5)
  48. fmt.Println(slice1)
  49.  
  50. transInterface(slice1)
  51.  
  52. //var cat1 A = Cat{"MiaoMiao" , 3}
  53. //fmt.Println(cat1.name , cat1.age)
  54.  
  55. }
  56.  
  57. //接口对象转型
  58. //接口对象.(type),配合switch...case语句
  59. func transInterface(s []interface{}) {
  60. for i := range s {
  61. fmt.Println("第", i+ , "个数据:")
  62. switch t := s[i].(type) {
  63. case Cat:
  64. fmt.Printf("\t Cat对象,name属性:%s,age属性:%d \n" , t.name , t.age)
  65. case Person:
  66. fmt.Printf("\t Person对象,name属性:%s,sex属性:%s \n" , t.name , t.sex)
  67. case string:
  68. fmt.Println("\t string类型" , t)
  69. case int:
  70. fmt.Println("\t int类型" , t)
  71. case float64:
  72. fmt.Println("\t float64类型" , t)
  73. }
  74. }
  75. }
  76.  
  77. func showInfo(a A) {
  78. fmt.Printf("%T , %v \n", a, a)
  79. }

五、接口对象转型
1、 方式一:
• instance, ok :=接口对象.(实际类型)
•如果该接口对象是对应的实际类型,那么instance就是转型之后对象,ok的值为true
•配合if... else if...语句使用
2、 方式二:
•接口对象.(type)
•配合switch...case语句使用

  1. package main
  2.  
  3. import "fmt"
  4. import (
  5. "base"
  6. "math"
  7. )
  8.  
  9. //1、定义接口
  10. type Shape interface {
  11. perimeter() float64
  12. area() float64
  13. }
  14.  
  15. //2.矩形
  16. type Rectangle struct {
  17. a, b float64
  18. }
  19.  
  20. //3.三角形
  21. type Triangle struct {
  22. a, b, c float64
  23. }
  24.  
  25. //4.圆形
  26. type Circle struct {
  27. radius float64
  28. }
  29.  
  30. //定义实现接口的方法
  31. func (r Rectangle) perimeter() float64 {
  32. return (r.a + r.b) *
  33. }
  34.  
  35. func (r Rectangle) area() float64 {
  36. return r.a * r.b
  37. }
  38.  
  39. func (t Triangle) perimeter() float64 {
  40. return t.a + t.b + t.c
  41. }
  42.  
  43. func (t Triangle) area() float64 {
  44. //海伦公式
  45. p := t.perimeter() / //半周长
  46. return math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))
  47. }
  48.  
  49. func (c Circle) perimeter() float64 {
  50. return * math.Pi * c.radius
  51. }
  52.  
  53. func (c Circle) area() float64 {
  54. return math.Pow(c.radius, ) * math.Pi
  55. }
  56.  
  57. //接口对象转型方式1
  58. //instance,ok := 接口对象.(实际类型)
  59. func getType(s Shape) {
  60. if instance, ok := s.(Rectangle); ok {
  61. fmt.Printf("矩形:长度%.2f , 宽度%.2f , ", instance.a, instance.b)
  62. } else if instance, ok := s.(Triangle); ok {
  63. fmt.Printf("三角形:三边分别:%.2f , %.2f , %.2f , ", instance.a, instance.b, instance.c)
  64. } else if instance, ok := s.(Circle); ok {
  65. fmt.Printf("圆形:半径%.2f , ", instance.radius)
  66. }
  67. }
  68.  
  69. //接口对象转型——方式2
  70. //接口对象.(type), 配合switch和case语句使用
  71. func getType2(s Shape) {
  72. switch instance := s.(type) {
  73. case Rectangle:
  74. fmt.Printf("矩形:长度为%.2f , 宽为%.2f ,\t", instance.a, instance.b)
  75. case Triangle:
  76. fmt.Printf("三角形:三边分别为%.2f ,%.2f , %.2f ,\t", instance.a, instance.b, instance.c)
  77. case Circle:
  78. fmt.Printf("圆形:半径为%.2f ,\t", instance.radius)
  79. }
  80. }
  81.  
  82. func getResult(s Shape) {
  83. getType2(s)
  84. fmt.Printf("周长:%.2f ,面积:%.2f \n", s.perimeter(), s.area())
  85. }
  86.  
  87. func main() {
  88. var s Shape
  89. s = Rectangle{, }
  90. getResult(s)
  91. showInfo(s)
  92.  
  93. s = Triangle{, , }
  94. getResult(s)
  95. showInfo(s)
  96.  
  97. s = Circle{}
  98. getResult(s)
  99. showInfo(s)
  100.  
  101. x := Triangle{, , }
  102. fmt.Println(x)
  103.  
  104. }
  105.  
  106. func (t Triangle) String() string {
  107. return fmt.Sprintf("Triangle对象,属性分别为:%.2f, %.2f, %.2f", t.a, t.b, t.c)
  108. }
  109.  
  110. func showInfo(s Shape) {
  111. fmt.Printf("%T ,%v \n", s, s)
  112. fmt.Println("-------------------")
  113. }

GO基础之接口的更多相关文章

  1. 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait

    [源码下载] 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait 作者:webabcd 介绍速战速决 之 PHP 类基础 抽象类 接口 trait 示例1.类的相关知识点 1(基础 ...

  2. [.net 面向对象编程基础] (16) 接口

    [.net 面向对象编程基础] (16) 接口 关于“接口”一词,跟我们平常看到的电脑的硬件“接口”意义上是差不多的.拿一台电脑来说,我们从外面,可以看到他的USB接口,COM接口等,那么这些接口的目 ...

  3. spring中基础核心接口总结

    spring中基础核心接口总结理解这几个接口,及其实现类就可以快速了解spring,具体的用法参考其他spring资料 1.BeanFactory最基础最核心的接口重要的实现类有:XmlBeanFac ...

  4. Go语言基础之接口

    Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口介绍 在Go语言中接口(interface)是一种类型,一种抽象的类 ...

  5. C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态

    C#基础--类/接口/成员修饰符,多态.重载.重写,静态和非静态 类/接口/成员修饰符 C#修饰符---接口: 接口默认访问符是internal接口的成员默认访问修饰符是public C#修饰符--类 ...

  6. Java基础十--接口

    Java基础十--接口 一.接口的定义和实例 /* abstract class AbsDemo { abstract void show1(); abstract void show2(); } 8 ...

  7. Java基础-面向接口(interface)编程

    Java基础-面向接口(interface)编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的“类 ...

  8. GO学习-(14) Go语言基础之接口

    Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类 ...

  9. C#夯实基础之接口(《CLR via C#》读书笔记)

    一. 接口的类型 接口是引用类型.因此从值类型赋值给接口是需要装箱的.如下所示: class Program { static void Main(string[] args) { ISay catS ...

  10. Java基础10 接口的继承与抽象类

    链接地址:http://www.cnblogs.com/vamei/archive/2013/03/31/2982240.html 作者:Vamei 出处:http://www.cnblogs.com ...

随机推荐

  1. luogu P1908 逆序对 |树状数组

    题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为"逆序对"的 ...

  2. luogu P1582 倒水 |数学

    题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子.每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒 ...

  3. 初步认知jQuery

    jQuery:是JavaScript的一个类库全写JavaScript query   write less do more JavaScript查询写的更少做的更多 第一步先导入js文件: < ...

  4. [TimLinux] TCL 自定义包

    1. 包 很多功能存放在一起,定义为一个包,在iTcl(Incr TCL)之后,可以定义一个类,类可以放在一个包里面,包为一个独立的文件,可以为TCL文件,也可以为C/C++语言实现的动态库. 2. ...

  5. cf round 598div3 D.Binary String Minimizing

    题目:https://codeforces.com/contest/1256/problem/D 题意:给你长度为n的01串,能将任意两相邻字符交换k次,求最小字典序的交换结果. 思路:贪心...甚至 ...

  6. Codeforce-620C

    There are n pearls in a row. Let's enumerate them with integers from 1 to n from the left to the rig ...

  7. 洛谷 题解 P1736 【创意吃鱼法】

    题目大意 给出一个 \(n \times m \ (1 \leq n, \ m \leq 2500)\) 的 \(01\) 矩阵,让你在其中找到一个最大的子矩阵使得该子矩阵除了一条对角线上的数字均为 ...

  8. MooseFS 分布式存储

    一.MooseFS介绍 MooseFS主要由管理服务器(master).元日志服务器(Metalogger).数据存储服务器(chunkserver)构成. 管理服务器:主要作用是管理数据存储服务器, ...

  9. Python递归函数如何写?正确的Python递归函数用法

    前言本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归 ...

  10. Mint UI 之loadmore组件的坑:内部元素头部被遮挡了一部分

    前端经常会遇到数据分页加载的需求,mint-ui组件为大家提供了loadmore组件 但是我在使用的时候,遇到了一个问题:写好布局和样式以及逻辑之后,我的mt-loadmore标签的头部总是不顶在父元 ...