Go的多态

go 是一种强类型的语言,每当我从java切换到go时总有些许的不适应,但是追求优雅,就不应该妥协。

go没有 implements, extends 关键字,所以习惯于 OOP 编程,或许一开始会有点无所适从的感觉。 但go作为一种优雅的语言, 给我们提供了另一种解决方案, 那就是鸭子类型:看起来像鸭子, 那么它就是鸭子.

go中的多态比java的隐匿得多,严格上说没有多态,但可以利用接口进行,对于都实现了同一接口的两种对象,可以进行类似地向上转型,并且在此时可以对方法进行多态路由分发,完全代码如下

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. // Vehicle 是一个超级接口。是所有交通工具必须实现的接口
  6. // 实现这个接口需要实现两个方法,description(),medium()
  7. type Vehicle interface {
  8. description() string
  9. medium() string
  10. }
  11. // car 类型.
  12. type Car struct {
  13. doors int
  14. }
  15. // Boat 类型.
  16. type Boat struct {
  17. rudders int
  18. masts int
  19. }
  20. //description ... Car 实现 Vehicle接口的description方法
  21. // Vehicle interface.
  22. func (c Car) description() string {
  23. return fmt.Sprintf("I am a car with %v door(s). I move on the %v.", c.doors, c.medium())
  24. }
  25. // medium... Car 实现 Vehicle接口的medium方法
  26. func (c Car) medium() string {
  27. return "road"
  28. }
  29. // description ... Boat 实现 Vehicle接口的description方法
  30. func (b Boat) description() string {
  31. return fmt.Sprintf("I am a boat with %v rudder(s) and %v mast(s). I ride on %v.", b.rudders, b.masts, b.medium())
  32. }
  33. // medium... Boat 实现 Vehicle接口的medium方法
  34. func (b Boat) medium() string {
  35. return "water"
  36. }
  37. // ride ... 注意接口既能是一个只类型,也可以是一个引用类型。
  38. // 我们使用值类型(`Vehicle`)而不使用引用类型(`*Vehicle`)。
  39. // 参看 @See http://openmymind.net/Things-I-Wish-Someone-Had-Told-Me-About-Go/
  40. func ride(vehicle Vehicle) {
  41. fmt.Println(fmt.Sprintf("Literal Vehicle: Value is %v. Type is %T.", vehicle, vehicle))
  42. fmt.Println(vehicle.description())
  43. fmt.Println(fmt.Sprintf("Did you notice that the vehicle rides on %v?", vehicle.medium()))
  44. }
  45. // checkType ... 类型检查
  46. func checkType(vehicle Vehicle) {
  47. test1, ok1 := vehicle.(*Car)
  48. fmt.Println(fmt.Sprintf("Is %v a *Car? %v.", test1, ok1))
  49. test2, ok2 := vehicle.(Car)
  50. fmt.Println(fmt.Sprintf("Is %v a Car? %v.", test2, ok2))
  51. test3, ok1 := vehicle.(*Boat)
  52. fmt.Println(fmt.Sprintf("Is %v a *Boat? %v.", test3, ok1))
  53. test4, ok2 := vehicle.(Boat)
  54. fmt.Println(fmt.Sprintf("Is %v a Boat? %v.", test4, ok2))
  55. test5, ok3 := vehicle.(Vehicle)
  56. fmt.Println(fmt.Sprintf("Is %v a Vehicle? %v.", test5, ok3))
  57. }
  58. // main ...
  59. func main() {
  60. // Using & returns a pointer to the struct value.
  61. car := &Car{
  62. doors: 4,
  63. }
  64. // Not using & returns the struct value.
  65. boat := Boat{
  66. rudders: 1,
  67. masts: 3,
  68. }
  69. fmt.Println("Ride in the car!")
  70. ride(car)
  71. fmt.Println()
  72. fmt.Println("Ride in the boat!")
  73. ride(boat)
  74. fmt.Println()
  75. fmt.Println("Check the type of the car.")
  76. checkType(car)
  77. fmt.Println()
  78. fmt.Println("Check the type of the boat.")
  79. checkType(boat)
  80. fmt.Println()
  81. }

链接