接口

接口定义

使用interface关键字定义接口,跟go一样

默认是模块级别,使用pub变为公共级别

接口命名跟结构体一样,要求首字母大写,建议以er风格结尾,非强制

  1. pub interface Speaker {
  2. speak() string
  3. }

接口字段

接口在其他编程语言中大部分都只能包含方法签名

V语言中接口除了可以包含方法签名,也可以包含字段,虽然包含字段也可以转为方法签名,

但是直接约束字段,代码看起来更舒服.

编译时会检查结构体及其组合结构体(子类)是否实现接口字段,

只有字段名,字段类型,是否可变,都跟接口中的字段一致,才算实现了这个接口字段.

  1. module main
  2. interface PointInterface {
  3. mut:
  4. x int //定义接口包含字段
  5. y int
  6. }
  7. struct Point {
  8. mut:
  9. x int //接口字段实现
  10. y int
  11. }
  12. fn add(p1 PointInterface,p2 PointInterface) PointInterface {
  13. mut p:=Point {}
  14. p.x=p1.x+p2.x
  15. p.y=p1.y+p2.y
  16. return p
  17. }
  18. fn main() {
  19. p1:=Point{
  20. x:1
  21. y:2
  22. }
  23. p2:=Point {
  24. x:3
  25. y:4
  26. }
  27. p3:=add(p1,p2)
  28. println('x:$p3.x,y:$p3.y')
  29. }
  1. interface Animal {
  2. mut:
  3. name string
  4. }
  5. struct Cat {
  6. name string //mut不匹配,编译不通过
  7. }
  8. fn main() {
  9. mut animals := []Animal{}
  10. animals << Cat{}
  11. }

接口方法

接口也可以像结构体那样有自己的方法,只要结构体实现了接口,就可以调用接口的方法

  1. struct Cat {
  2. breed string
  3. }
  4. interface Animal {
  5. breed string
  6. }
  7. //接口自己实现的方法,接口方法的默认实现
  8. fn (a Animal) info() string {
  9. return "I'm a ${a.breed} ${typeof(a).name}"
  10. }
  11. fn new_animal(breed string) Animal {
  12. return &Cat{ breed }
  13. }
  14. fn main() {
  15. mut a := new_animal('persian')
  16. println(a.info())
  17. }

接口组合

接口也像结构体那样支持组合

  1. module main
  2. pub interface Reader{
  3. read(mut buf []byte) ?int
  4. }
  5. pub interface Writer {
  6. write(bug []byte) ?int
  7. }
  8. // 接口组合
  9. pub interface ReaderWriter {
  10. Reader
  11. Writer
  12. }
  13. //接口组合
  14. interface WalkerTalker {
  15. Walker
  16. Talker
  17. }
  18. interface Talker {
  19. nspeeches int
  20. talk(msg string)
  21. }
  22. interface Walker {
  23. nsteps int
  24. walk(newx int, newy int)
  25. }
  26. struct Abc {
  27. mut:
  28. x int
  29. y int
  30. phrases []string
  31. nsteps int = 1000 //实现接口中要求的字段
  32. nspeeches int = 1000 //实现接口中要求的字段
  33. }
  34. //实现接口要求的方法
  35. fn (mut s Abc) talk(msg string) {
  36. s.phrases << msg
  37. s.nspeeches++
  38. }
  39. //实现接口要求的方法
  40. fn (mut s Abc) walk(x int, y int) {
  41. s.x = x
  42. s.y = y
  43. s.nsteps++
  44. }
  45. fn main() {
  46. mut wt := WalkerTalker(Abc{
  47. x: 1
  48. y: 1
  49. phrases: ['hi']
  50. })
  51. wt.talk('my name is Wally')
  52. wt.walk(100, 100)
  53. if wt is Abc {
  54. println(wt)
  55. }
  56. }

接口实现

没有接口实现的关键字,类型无需显示声明所要实现的接口,

鸭子类型:只要结构体实现了接口定义的方法,就满足该接口的使用

  1. module main
  2. struct Dog {}
  3. struct Cat {}
  4. fn (d Dog) speak() string {
  5. return 'woof'
  6. }
  7. fn (c Cat) speak() string {
  8. return 'meow'
  9. }
  10. interface Speaker {
  11. speak() string
  12. }
  13. fn perform(s Speaker) {
  14. println(s.speak())
  15. }
  16. fn main() {
  17. dog := Dog{}
  18. cat := Cat{}
  19. perform(dog) // "woof"
  20. perform(cat) // "meow"
  21. }

接口可以作为结构体字段类型使用:

  1. struct Foo {
  2. speaker Speaker //接口类型字段
  3. speakers []Speaker //接口类型数组字段
  4. }

获取接口变量的具体类型

接口类型使用内置方法type_name()来返回接口变量的具体类型

  1. module main
  2. pub interface Animal {
  3. speak() string
  4. }
  5. pub struct Cat {}
  6. pub fn (c Cat) speak() string {
  7. return 'miao'
  8. }
  9. pub struct Dog {}
  10. pub fn (d Dog) speak() string {
  11. return 'wang'
  12. }
  13. pub fn say(animal Animal) {
  14. println(typeof(animal).name) // 只会返回接口名字Animal,不会返回具体类型
  15. println(animal.type_name()) // 返回接口的具体类型
  16. println(animal.speak())
  17. }
  18. fn main() {
  19. cat:=Cat {}
  20. say(cat)
  21. dog:=Dog{}
  22. say(dog)
  23. }

接口变量类型判断及匹配

使用is,!is对接口参数的具体类型进行判断

使用as对接口参数进行类型转换

使用match对接口类型参数进行匹配,跟match匹配联合类型一样,每一个分支都会自动造型,非常的好用

  1. module main
  2. struct Dog {
  3. name1 string
  4. }
  5. struct Cat {
  6. name2 string
  7. }
  8. fn (d Dog) speak() string {
  9. return 'wang'
  10. }
  11. fn (c Cat) speak() string {
  12. return 'miao'
  13. }
  14. interface Speaker {
  15. speak() string
  16. }
  17. fn perform(s Speaker) {
  18. if s is Dog { // 通过is操作符,判断接口类型是否是某一个具体类型
  19. println('s is Dog')
  20. }
  21. if s !is Dog { // 通过!is操作符,判断接口类型不是某一个具体类型
  22. println('s is not Dog')
  23. }
  24. //match对接口参数的类型匹配,跟匹配联合类型一样,每一个分支都会自动造型,非常的好用
  25. match s {
  26. Dog { println('s is Dog struct,name is $s.name1') }
  27. Cat { println('s is Cat struct,name is $s.name2') }
  28. else { println('s is: $s.type_name()') }
  29. }
  30. }
  31. fn main() {
  32. dog := Dog{ name1:'dog' }
  33. cat := Cat{ name2:'cat' }
  34. perform(dog) // "wang"
  35. perform(cat) // "miao"
  36. }

判断类型是否实现接口

  1. module main
  2. struct Dog {
  3. name string
  4. }
  5. struct Foo {
  6. }
  7. fn (d Dog) speak() string {
  8. return 'wang'
  9. }
  10. interface Speaker {
  11. speak() string
  12. }
  13. fn my_fn<T>() {
  14. $if T is Speaker { //使用$if,在泛型函数中判断类型是否实现了某个接口
  15. println('type T implements Speaker interface')
  16. } $else {
  17. println('type T do not implements Speaker interface')
  18. }
  19. }
  20. fn main() {
  21. my_fn<Dog>()
  22. // my_fn<Foo>()
  23. // $if Dog is Speaker {
  24. // println('type Dog implements Speaker interface')
  25. // }
  26. }