结构体
结构体定义
结构体命名必须是大写字母开头,如果是小写字母开头会编译报错
1. struct Point {
2. x int
3. y int
4. }
6. fn main() {
7. p := Point{
8. x: 10
9. y: 20
10. }
11. println(p.x) // 结构体字段通过点号来访问
12. }
结构体被分配到内存的栈中,引用类型
取结构体地址:&
1. p2 := &Point{10, 10}
2. println(p2.x)
空结构体:
1. struct Empty {}
3. fn main() {
4. println(sizeof(Empty)) //空结构体占用内存的大小为0
5. }
结构体占用内存:
sizeof( )可以返回结构体占用内存字节大小
字段
结构体字段默认也是不可变,使用mut为可变
结构体字段的可变性和访问控制,参考访问控制章节
如果结构体字段名需要是关键字,可以通过使用@作为前缀也可以编译通过
这一点在跟C库集成时,比较常用,一些C库的struct的字段有些刚好是V的关键字,可以使用@前缀,编译成C代码时@前缀会被去掉,刚好就是C的struct中的字段名
1. struct Foo {
2. @type string
3. }
5. fn main() {
6. foo := Foo{ @type: 'test' }
7. println(foo.@type)
8. }
结构体字段支持默认值
1. struct Foo {
2. a int
3. b int = 7 //默认值7
4. }
6. fn main() {
7. foo := Foo{
8. a: 1
9. }
10. println(foo.a) //输出1
11. println(foo.b) //输出默认值7
12. foo2 := Foo{
13. a: 1
14. b: 2
15. }
16. println(foo2.b) //输出2
17. }
结构体字段的类型可以是任何类型,甚至可以是函数类型
1. module main
3. struct Abc {
4. f1 int
5. f2 int
6. f3 fn (int, int) int //结构体字段类型为函数类型
7. }
9. fn add(x int, y int) int {
10. return x + y
11. }
13. fn main() {
14. a1 := Abc{
15. f1: 123
16. f3: fn (x int, y int) int {
17. return x + y
18. }
19. }
20. a2 := Abc{
21. f1: 123
22. f2: 789
23. f3: add
24. }
25. println(a1)
26. println(a2)
27. }
结构体字段初始化时必录
1. struct Point {
2. x int
3. y int
4. z int [required] //字段注解required表示必须初始化赋值
5. }
7. fn main() {
8. a := Point{
9. // x: 1 //不会报错,x不是必须初始化赋值
10. y: 3
11. z: 5
12. }
13. b := Point{
14. x: 2
15. y: 4
16. // z: 6 //报错: field `Point.z` must be initialized
17. }
18. println(a)
19. println(b)
20. }
结构体变量可以基于另一个变量创建,同时合并新的字段值
1. module main
3. struct City {
4. name string
5. population int
6. }
8. struct Country {
9. name string
10. capital City
11. }
13. fn main() {
14. c := Country{
15. name: 'test'
16. capital: City{
17. name: 'city'
18. }
19. }
20. c2 := Country{
21. ...c // 在c的基础上创建c2变量
22. capital: City{
23. name: 'city2'
24. population: 200
25. }
26. }
27. println(c2)
28. }
短字面量创建结构体变量
当函数的参数是结构体变量时,这个语法可以简化结构体变量的创建,这个语法在ui模块比较常用到,用来简化函数参数
1. module main
3. struct User {
4. name string
5. age int
6. }
8. fn add(u User) {
9. println(u)
10. }
12. fn main(){
13. add(User{name:'jack',age:22}) //标准方式
14. add({name:'tom',age:23}) //简短方式,省略类型
15. add(name:'tt',age:33) //更简短的方式,省略类型和大括号,这个用法感觉分辨不出来参数是结构体,推荐使用方式二,兼具简短和清晰性
16. }
访问控制
结构体默认是模块级别的,使用pub关键字定义公共级别
1. pub struct Point { //公共级别,可以被别的模块使用
2. x int
3. y int
4. }
组合
跟go一样,V的结构体没有继承,但是有组合,可以用组合来实现继承一样的效果,甚至可以多个组合
1. module main
3. struct Widget {
4. mut:
5. x int
6. y int
7. }
9. pub fn (mut w Widget) move(x_step int, y_step int) {
10. w.x += x_step
11. w.y += y_step
12. }
14. struct Widget2 {
15. mut:
16. z int
17. }
19. pub fn (mut w Widget2) move_z(z_step int) {
20. w.z += z_step
21. }
23. struct Button {
24. Widget //组合
25. Widget2 //多个组合
26. title string
27. }
29. fn main() {
30. mut button := Button{
31. title: 'Click me'
32. }
33. button.x = 3 // Button的x字段来自Widget
34. button.z = 4 // Button的z字段来自Widget2
35. println('x:$button.x,y:$button.y,z:$button.z')
36. button.move(3, 4) // Button的move方法来自Widget
37. println('x:$button.x,y:$button.y,z:$button.z')
38. button.move_z(5) // Button的move_z方法来自Widget2
39. println('x:$button.x,y:$button.y,z:$button.z')
40. }
泛型结构体
参考泛型章节
结构体注解
结构体像函数那样支持注解,可以针对结构体,结构体字段,结构体方法进行注解
[typedef]
1. [typedef]
2. struct Point {
3. }
typedef注解目前主要用在集成C代码库,详细参考:
[heap]
heap表示该结构体只能在内存的堆上创建,只能以引用的形式被使用
1. [heap]
2. struct Window { //只能通过引用的形式(&Window)来使用这个结构体
3. }
可以参考标准库sync中WaitGroup的实际使用
vlib/sync/waitgroup.v
1. [heap]
2. struct WaitGroup {
3. mut:
4. task_count int
5. task_count_mutex &Mutex = &Mutex(0)
6. wait_blocker &Waiter = &Waiter(0)
7. }
9. pub fn new_waitgroup() &WaitGroup { //不能被复制,只能以引用的方式被使用
10. return &WaitGroup{
11. task_count_mutex: new_mutex()
12. wait_blocker: new_waiter()
13. }
14. }
[noinit]
使用[noinit]标志后,结构体只能在本模块内使用Foo{}来创建变量,在其他模块中被禁止使用Foo{}来初始化变量
1. module mymodule
3. [noinit]
4. pub struct Result {
5. }
1. module main
3. import mymodule
5. fn main() {
6. res := mymodule.Result{}
7. println(res)
8. }
结构体字段注解
- 用于内置json解析支持
详细参考:json章节 2. 结构体字段必须初始化赋值注解
1. struct Point {
2. x int
3. y int
4. z int [required] //字段注解required表示必须初始化赋值
5. }
7. fn main() {
8. a := Point{
9. // x: 1 //不会报错,x不是必须初始化赋值
10. y: 3
11. z: 5
12. }
13. b := Point{
14. x: 2
15. y: 4
16. // z: 6 //报错: field `Point.z` must be initialized
17. }
18. println(a)
19. println(b)
20. }
结构体方法注解
跟函数注解一样,也可以对结构体方法进行注解
1. [inline] //方法注解
2. pub fn (p Point) position() (int, int) {
3. return p.x, p.y
4. }
结构体反射
可以通过编译时反射,实现动态获取结构体的所有字段,素有方法,并且可以动态设置字段值
具体可以参考编译时反射章节
结构体字段内存位置偏移
__offsetof函数实现C的offsetof函数那样,返回结构体中某个字段的内存偏移量
1. module main
3. struct User {
4. name [50]byte
5. age int
6. desc string
7. }
9. fn main() {
10. offset_name:=__offsetof(User,name)
11. offset_age:=__offsetof(User,age)
12. offset_desc:=__offsetof(User,desc)
13. println(offset_name)
14. println(offset_age)
15. println(offset_desc)
16. }
