接口

接口定义

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

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

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

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

接口字段

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

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

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

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

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

1. module main

3. interface PointInterface {
4. mut:
5. x int //定义接口包含字段
6. y int
7. }

9. struct Point {
10. mut:
11. x int //接口字段实现
12. y int
13. }

15. fn add(p1 PointInterface,p2 PointInterface) PointInterface {
16. mut p:=Point {}
17. p.x=p1.x+p2.x
18. p.y=p1.y+p2.y
19. return p
20. }

22. fn main() {
23. p1:=Point{
24. x:1
25. y:2
26. }
27. p2:=Point {
28. x:3
29. y:4
30. }
31. p3:=add(p1,p2)
32. println('x:$p3.x,y:$p3.y')
33. }
1. interface Animal {
2. mut:
3. name string
4. }

6. struct Cat {
7. name string //mut不匹配,编译不通过
8. }

10. fn main() {
11. mut animals := []Animal{}
12. animals << Cat{}
13. }

接口方法

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

1. struct Cat {
2. breed string
3. }

5. interface Animal {
6. breed string
7. }

9. //接口自己实现的方法,接口方法的默认实现
10. fn (a Animal) info() string {
11. return "I'm a ${a.breed} ${typeof(a).name}"
12. }

14. fn new_animal(breed string) Animal {
15. return &Cat{ breed }
16. }

18. fn main() {
19. mut a := new_animal('persian')
20. println(a.info())
21. }

接口组合

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

1. module main

3. pub interface Reader{
4. read(mut buf []byte) ?int
5. }

7. pub interface Writer {
8. write(bug []byte) ?int
9. }

11. // 接口组合
12. pub interface ReaderWriter {
13. Reader
14. Writer
15. }

17. //接口组合
18. interface WalkerTalker {
19. Walker
20. Talker
21. }

23. interface Talker {
24. nspeeches int
25. talk(msg string)
26. }

28. interface Walker {
29. nsteps int
30. walk(newx int, newy int)
31. }

33. struct Abc {
34. mut:
35. x         int
36. y         int
37. phrases   []string
38. nsteps    int = 1000 //实现接口中要求的字段
39. nspeeches int = 1000 //实现接口中要求的字段
40. }

42. //实现接口要求的方法
43. fn (mut s Abc) talk(msg string) {
44. s.phrases << msg
45. s.nspeeches++
46. }

48. //实现接口要求的方法
49. fn (mut s Abc) walk(x int, y int) {
50. s.x = x
51. s.y = y
52. s.nsteps++
53. }

55. fn main() {
56. mut wt := WalkerTalker(Abc{
57. x: 1
58. y: 1
59. phrases: ['hi']
60. })
61. wt.talk('my name is Wally')
62. wt.walk(100, 100)
63. if wt is Abc {
64. println(wt)
65. }
66. }

接口实现

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

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

1. module main

3. struct Dog {}

5. struct Cat {}

7. fn (d Dog) speak() string {
8. return 'woof'
9. }

11. fn (c Cat) speak() string {
12. return 'meow'
13. }

15. interface Speaker {
16. speak() string
17. }

19. fn perform(s Speaker) {
20. println(s.speak())
21. }

23. fn main() {
24. dog := Dog{}
25. cat := Cat{}
26. perform(dog) // "woof"
27. perform(cat) // "meow"
28. }

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

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

获取接口变量的具体类型

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

1. module main

3. pub interface Animal {
4. speak() string
5. }

7. pub struct Cat {}
8. pub fn (c Cat) speak() string {
9. return 'miao'
10. }

12. pub struct Dog {}

14. pub fn (d Dog) speak() string {
15. return 'wang'
16. }

18. pub fn say(animal Animal) {
19. println(typeof(animal).name) // 只会返回接口名字Animal,不会返回具体类型
20. println(animal.type_name()) // 返回接口的具体类型
21. println(animal.speak())
22. }

24. fn main() {
25. cat:=Cat {}
26. say(cat)

28. dog:=Dog{}
29. say(dog)
30. }

接口变量类型判断及匹配

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

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

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

1. module main

3. struct Dog {
4. name1 string
5. }

7. struct Cat {
8. name2 string
9. }

11. fn (d Dog) speak() string {
12. return 'wang'
13. }

15. fn (c Cat) speak() string {
16. return 'miao'
17. }

19. interface Speaker {
20. speak() string
21. }

23. fn perform(s Speaker) {
24. if s is Dog { // 通过is操作符,判断接口类型是否是某一个具体类型
25. println('s is Dog')
26. }
27. if s !is Dog { // 通过!is操作符,判断接口类型不是某一个具体类型
28. println('s is not Dog')
29. }

31. //match对接口参数的类型匹配,跟匹配联合类型一样,每一个分支都会自动造型,非常的好用
32. match s {
33. Dog { println('s is Dog struct,name is $s.name1') }
34. Cat { println('s is Cat struct,name is $s.name2') }
35. else { println('s is: $s.type_name()') }
36. }
37. }

39. fn main() {
40. dog := Dog{ name1:'dog' }
41. cat := Cat{ name2:'cat' }
42. perform(dog) // "wang"
43. perform(cat) // "miao"
44. }

判断类型是否实现接口

1. module main

3. struct Dog {
4. name string
5. }

7. struct Foo {
8. }

10. fn (d Dog) speak() string {
11. return 'wang'
12. }

14. interface Speaker {
15. speak() string
16. }

18. fn my_fn<T>() {
19. $if T is Speaker { //使用$if,在泛型函数中判断类型是否实现了某个接口
20. println('type T implements Speaker interface')
21. } $else {
22. println('type T do not implements Speaker interface')
23. }
24. }

26. fn main() {
27. my_fn<Dog>()
28. // my_fn<Foo>()

30. // $if Dog is Speaker {
31. //     println('type Dog implements Speaker interface')
32. // }
33. }