结构体被分配到内存的栈中,引用类型

    取结构体地址:&

    1. println(p2.x)

    空结构体:

    1. struct Empty {}
    2. fn main() {
    3. println(sizeof(Empty)) //空结构体占用内存的大小为0
    4. }

    结构体占用内存:

    sizeof( )可以返回结构体占用内存字节大小

    字段

    结构体字段默认也是不可变,使用mut为可变

    结构体字段的可变性和访问控制,参考章节

    如果结构体字段名需要是关键字,可以通过使用@作为前缀也可以编译通过

    这一点在跟C库集成时,比较常用,一些C库的struct的字段有些刚好是V的关键字,可以使用@前缀,编译成C代码时@前缀会被去掉,刚好就是C的struct中的字段名

    1. struct Foo {
    2. @type string
    3. }
    4. fn main() {
    5. foo := Foo{ @type: 'test' }
    6. println(foo.@type)
    7. }

    结构体字段支持默认值

    1. struct Foo {
    2. a int
    3. b int = 7 //默认值7
    4. }
    5. fn main() {
    6. foo := Foo{
    7. a: 1
    8. }
    9. println(foo.a) //输出1
    10. println(foo.b) //输出默认值7
    11. foo2 := Foo{
    12. a: 1
    13. b: 2
    14. }
    15. println(foo2.b) //输出2
    16. }
    1. module main
    2. struct Abc {
    3. f1 int
    4. f2 int
    5. f3 fn (int, int) int //结构体字段类型为函数类型
    6. }
    7. fn add(x int, y int) int {
    8. return x + y
    9. }
    10. fn main() {
    11. a1 := Abc{
    12. f1: 123
    13. f3: fn (x int, y int) int {
    14. return x + y
    15. }
    16. }
    17. a2 := Abc{
    18. f1: 123
    19. f2: 789
    20. f3: add
    21. }
    22. println(a1)
    23. println(a2)
    24. }

    结构体字段初始化时必录

    结构体变量可以基于另一个变量创建,同时合并新的字段值

    1. module main
    2. struct City {
    3. name string
    4. population int
    5. }
    6. struct Country {
    7. capital City
    8. }
    9. fn main() {
    10. c := Country{
    11. name: 'test'
    12. capital: City{
    13. name: 'city'
    14. }
    15. }
    16. c2 := Country{
    17. ...c // 在c的基础上创建c2变量
    18. capital: City{
    19. name: 'city2'
    20. population: 200
    21. }
    22. }
    23. println(c2)
    24. }

    短字面量创建结构体变量

    当函数的参数是结构体变量时,这个语法可以简化结构体变量的创建,这个语法在ui模块比较常用到,用来简化函数参数

    1. module main
    2. struct User {
    3. name string
    4. age int
    5. }
    6. fn add(u User) {
    7. println(u)
    8. }
    9. fn main(){
    10. add(User{name:'jack',age:22}) //标准方式
    11. add({name:'tom',age:23}) //简短方式,省略类型
    12. add(name:'tt',age:33) //更简短的方式,省略类型和大括号,这个用法感觉分辨不出来参数是结构体,推荐使用方式二,兼具简短和清晰性
    13. }

    访问控制

    结构体默认是模块级别的,使用pub关键字定义公共级别

    1. pub struct Point { //公共级别,可以被别的模块使用
    2. x int
    3. y int
    4. }

    跟go一样,V的结构体没有继承,但是有组合,可以用组合来实现继承一样的效果,甚至可以多个组合

    1. module main
    2. struct Widget {
    3. mut:
    4. x int
    5. y int
    6. }
    7. pub fn (mut w Widget) move(x_step int, y_step int) {
    8. w.x += x_step
    9. w.y += y_step
    10. }
    11. struct Widget2 {
    12. mut:
    13. z int
    14. }
    15. pub fn (mut w Widget2) move_z(z_step int) {
    16. w.z += z_step
    17. }
    18. struct Button {
    19. Widget //组合
    20. title string
    21. }
    22. fn main() {
    23. mut button := Button{
    24. title: 'Click me'
    25. }
    26. button.x = 3 // Button的x字段来自Widget
    27. button.z = 4 // Button的z字段来自Widget2
    28. println('x:$button.x,y:$button.y,z:$button.z')
    29. button.move(3, 4) // Button的move方法来自Widget
    30. println('x:$button.x,y:$button.y,z:$button.z')
    31. button.move_z(5) // Button的move_z方法来自Widget2
    32. println('x:$button.x,y:$button.y,z:$button.z')
    33. }

    泛型结构体

    参考泛型章节

    结构体注解

    结构体像函数那样支持注解,可以针对结构体,结构体字段,结构体方法进行注解

    [typedef]

    1. [typedef]
    2. struct Point {
    3. }

    typedef注解目前主要用在集成C代码库,详细参考:

    heap表示该结构体只能在内存的堆上创建,只能以引用的形式被使用

    可以参考标准库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. }
    8. pub fn new_waitgroup() &WaitGroup { //不能被复制,只能以引用的方式被使用
    9. return &WaitGroup{
    10. task_count_mutex: new_mutex()
    11. wait_blocker: new_waiter()
    12. }
    13. }

    [noinit]

    使用[noinit]标志后,结构体只能在本模块内使用Foo{}来创建变量,在其他模块中被禁止使用Foo{}来初始化变量

    1. module mymodule
    2. [noinit]
    3. pub struct Result {
    4. }
    1. module main
    2. import mymodule
    3. fn main() {
    4. res := mymodule.Result{}
    5. println(res)
    6. }
    1. 用于内置json解析支持

      详细参考:

    2. 结构体字段必须初始化赋值注解

    1. struct Point {
    2. x int
    3. y int
    4. z int [required] //字段注解required表示必须初始化赋值
    5. }
    6. fn main() {
    7. a := Point{
    8. // x: 1 //不会报错,x不是必须初始化赋值
    9. y: 3
    10. z: 5
    11. }
    12. b := Point{
    13. x: 2
    14. y: 4
    15. // z: 6 //报错: field `Point.z` must be initialized
    16. }
    17. println(a)
    18. println(b)
    19. }

    结构体方法注解

    跟函数注解一样,也可以对结构体方法进行注解

    1. [inline] //方法注解
    2. pub fn (p Point) position() (int, int) {
    3. return p.x, p.y

    结构体反射

    可以通过编译时反射,实现动态获取结构体的所有字段,素有方法,并且可以动态设置字段值

    __offsetof函数实现C的offsetof函数那样,返回结构体中某个字段的内存偏移量