struct Foo {
a int
b int = 7 //默认值7
}
fn main() {
foo := Foo{
a: 1
}
println(foo.a) //输出1
println(foo.b) //输出默认值7
foo2 := Foo{
a: 1
b: 2
}
println(foo2.b) //输出2
}
结构体字段的类型可以是任何类型,甚至可以是函数类型:
module main
struct Abc {
f1 int
f2 int
f3 fn (int, int) int //结构体字段类型为函数类型
}
fn add(x int, y int) int {
return x + y
}
fn main() {
a1 := Abc{
f1: 123
f3: fn (x int, y int) int {
return x + y
}
}
a2 := Abc{
f1: 123
f2: 789
f3: add
}
println(a1)
println(a2)
}
结构体字段初始化时必录:
struct Point {
x int
y int
z int [required] //字段注解required表示必须初始化赋值
}
fn main() {
a := Point{
// x: 1 //不会报错,x不是必须初始化赋值
y: 3
z: 5
}
b := Point{
x: 2
y: 4
// z: 6 //报错: field `Point.z` must be initialized
}
println(a)
println(b)
}
结构体变量可以基于另一个变量创建,同时合并新的字段值:
module main
struct City {
name string
population int
}
struct Country {
name string
capital City
}
fn main() {
c := Country{
name: 'test'
capital: City{
name: 'city'
}
}
c2 := Country{
...c // 在c的基础上创建c2变量
capital: City{
name: 'city2'
population: 200
}
}
println(c2)
}
module main
struct User {
name string
age int
}
fn add(u User) {
println(u)
}
fn main(){
add(User{name:'jack',age:22}) //标准方式
add(name:'tt',age:33) //简短的方式,省略类型和大括号,有命名参数调用的感觉
}
选项字段:
跟函数的返回值类似:字段类型前加问号?表示:字段可能返回正常的类型或返回空值,即 T | none,如果字段返回none,则会触发空值错误,进入or代码块。
module main
struct Foo {
mut:
x ?int = 1 //字段可以返回正常类型或者none
y ?int = none //字段默认值为none,触发空值错误,进入or代码块
}
fn main() {
mut f := Foo{}
println(f.x?) //输出1
f = Foo{
x: 2
y: none
}
a := f.x or { 123 }
println(a) // 输出2
b := f.y or { 9999 } // f.y返回空值none,触发空值错误,进入or代码块
println(b) // 输出9999
mut sum := f.x? + 1
sum = f.x or { 123 } + 1
println(sum) // 输出3
}
访问控制
结构体默认是模块级别的,使用pub关键字定义公共级别。
pub struct Point { //公共级别,可以被别的模块使用
x int
y int
}
组合
跟go一样,V的结构体没有继承,但是有组合,可以用组合来实现继承一样的效果,多个组合也是可以的。
module main
struct Widget {
mut:
x int
y int
}
pub fn new_widget(x int, y int) Widget {
return Widget{
x: x
y: y
}
}
pub fn (mut w Widget) move(x_step int, y_step int) {
w.x += x_step
w.y += y_step
}
struct Widget2 {
mut:
z int
}
pub fn new_widget2(z int) Widget2 {
return Widget2{
z: z
}
}
pub fn (mut w Widget2) move_z(z_step int) {
w.z += z_step
}
struct Button {
Widget //组合
Widget2 //多个组合
title string
}
fn main() {
mut button := Button{
title: 'Click me'
}
button.x = 3 // Button的x字段来自Widget
button.z = 4 // Button的z字段来自Widget2
println('x:$button.x,y:$button.y,z:$button.z')
button.move(3, 4) // Button的move方法来自Widget
println('x:$button.x,y:$button.y,z:$button.z')
button.move_z(5) // Button的move_z方法来自Widget2
println('x:$button.x,y:$button.y,z:$button.z')
}
匿名结构体
在定义结构体字段时,除了使用已经定义好的结构体作为类型,也可以使用匿名结构体。
module main
struct Book {
x string
author struct { //匿名结构体
name string
age int
}
author2 struct { //匿名结构体也可以是空结构体
}
title string
}
fn main() {
book := Book{
author: struct {'sdf', 23} // 初始化匿名结构体字段时,也需要使用struct关键字
author2: struct {}
}
println(book)
println(book.author.age)
}
module main
struct Point {
x int
y int
}
struct Window {
pub:
p &Point = unsafe { nil } // 空值初始化引用类型字段,替代原来的voidptr(0)值
}
fn main() {
p := &Point{1,3}
w := Window { p:p }
println(w)
}
module mymodule
@[noinit]
pub struct Result {
}
//模块内的构造函数
pub fn new_result() Result {
return Result{}
}
module main
import mymodule
fn main() {
// 报错:it cannot be initialized with `mymodule.Result{}`
// res := mymodule.Result{}
res := mymodule.new_result() //调用模块提供的构造函数是可以的
println(res)
}
@[table: 'userlist'] //自定义表名
struct User {
id int [primary; sql: serial]
age int
name string [sql: 'username']
is_customer bool
skipped_string string [skip]
}
module main
struct Foo {
a i64 // 8字节
b int // 4字节
}
@[packed]
struct Bar {
a i64
b int
}
pub fn main() {
println(sizeof(Foo)) // 16,编译器会进行内存对齐
println(sizeof(Bar)) // 12,不让编译器进行内存对齐
}
struct Point {
x int
y int
z int [required] //字段注解required表示必须初始化赋值
}
fn main() {
a := Point{
// x: 1 //不会报错,x不是必须初始化赋值
y: 3
z: 5
}
b := Point{
x: 2
y: 4
// z: 6 //报错: field `Point.z` must be initialized
}
println(a)
println(b)
}
@[deprecated]
结构体字段作废
可以将结构体的某个字段标注为作废字段,并且可以加上作废开始日期。
只有在其他模块中直接访问作废字段,才会出发过期作废的提示或警告。
abc.v
module abc
pub struct Point {
pub mut:
x_new int
x int [deprecated: 'use Point.x_new instead'; deprecated_after: '2999-03-01']
}
main.v
module main
import abc
fn main() {
a := abc.Point{
x: 1
}
println(a.x) //直接访问了结构体的作废字段,就会提示或警告
}
module main
struct User {
name [50]u8
age int
desc string
}
fn main() {
offset_name:=__offsetof(User,name)
offset_age:=__offsetof(User,age)
offset_desc:=__offsetof(User,desc)
println(offset_name)
println(offset_age)
println(offset_desc)
}