// FieldData holds information about a field. Fields reside on structs.pubstructFieldData {pub: name string// the name of the field f typ int// the internal TypeID of the field f, unaliased_typ int// if f's type was an alias of int, this will be TypeID(int)// attrs []string// the attributes of the field f is_pub bool// f is in a `pub:` section is_mut bool// f is in a `mut:` section// is_shared bool// `f shared Abc` is_atomic bool// `f atomic int` , TODO is_option bool// `f ?string` , TODO// is_array bool// `f []string` , TODO is_map bool// `f map[string]int` , TODO is_chan bool// `f chan int` , TODO is_enum bool// `f Enum` where Enum is an enum is_struct bool// `f Abc` where Abc is a struct , TODO is_alias bool// `f MyInt` where `type MyInt = int`, TODO// indirections u8// 0 for `f int`, 1 for `f &int`, 2 for `f &&int` , TODO}
structApp { a string b stringmut: c int d f32pub: e f32 f u64pubmut: g string h u8}@['foo/bar/three']fn (mut app App) run() {}@['attr2']fn (mut app App) method2() {}fn (mut app App) int_method1() int {return0}fn (mut app App) int_method2() int {return1}fn (mut app App) string_arg(x string) {}fnno_lines(s string) string {return s.replace('\n',' ')}fnf1() {println(@FN) methods := ['run','method2','int_method1','int_method2','string_arg'] $for method in App.methods { //遍历结构体所有方法println(' method: $method.name | '+no_lines('$method'))assert method.name in methods }}fnf2() {println(@FN) $for method in App.methods { //遍历结构体所有方法println(' method: '+no_lines('$method'))$if method.typ is fn () {assert method.name in ['run','method2'] }$if method.return_type is int {assert method.name in ['int_method1','int_method2'] }$if method.args[0].typ is string {assert method.name =='string_arg' } }}fnmain() {println(@FN) $for field in App.fields { //遍历结构体所有字段println(' field: $field.name | '+no_lines('$field'))$if field.typ is string {assert field.name in ['a','b','g'] }$if field.typ is f32 {assert field.name in ['d','e'] }if field.is_mut {assert field.name in ['c','d','g','h'] }if field.is_pub {assert field.name in ['e','f','g','h'] }if field.is_pub && field.is_mut {assert field.name in ['g','h'] } }f1()f2()}
编译时动态字段赋值
structFoo { immutable intmut: test string name string}fncomptime_field_selector_read[T]() []string {mut t := T{} t.name ='2' t.test ='1'mut value_list := []string{} $for f in T.fields {$if f.typ is string { value_list << t.$f.name } }return value_list}fntest_comptime_field_selector_read() {assert comptime_field_selector_read[Foo]() == ['1','2']}fncomptime_field_selector_write[T]() T {mut t := T{} $for f in T.fields {$if f.typ is string { t.$f.name ='1' }$if f.typ is int { t.$f.name =1 } }return t}fntest_comptime_field_selector_write() { res := comptime_field_selector_write[Foo]()assert res.immutable ==1assert res.test =='1'assert res.name =='1'}structFoo2 { f Foo}fnnested_with_parentheses[T]() T {mut t := T{} $for f in T.fields {$if f.typ is Foo { t.$(f.name).test ='1' } }return t}fntest_nested_with_parentheses() { res := nested_with_parentheses[Foo2]()assert res.f.test =='1'}
编译时获取结构体字段信息
可以在$for循环中获取结构体字段的信息:
module mainstructAbc { x int y int name string}structMyStruct { s string [primary; sql: serial] i int ch_i chan int atomic_i atomicint// pointer1_i &int=unsafe { nil } pointer2_i &&int=unsafe { nil } pointer3_i &&&int=unsafe { nil }// array_i []int map_i map[int]int my_struct Abc my_struct_shared shared Abc// o_s ?string o_i ?int o_ch_i ?chan int= chan int{cap: 10} o_pointer1_i ?&int=unsafe { nil } o_pointer2_i ?&&int=unsafe { nil } o_pointer3_i ?&&&int=unsafe { nil }// o_array_i ?[]int o_map_i ?map[int]int o_my_struct ?Abc o_my_struct_shared ?shared Abc}fnmain() { $for field in MyStruct.fields {println("field: ${field.name}")//使用内置函数可以得到的字段信息println(sizeof(field)) //字段内存大小println(typeof(field).idx) //字段类型的idprintln(typeof(field).name) //字段类型名字println(isreftype(field)) //字段类型是否为引用类型//使用FieldData可以得到的字段信息println(field.name) //字段名字println(field.typ) //字段的类型idprintln(field.unaliased_typ) //如果字段类型是类型别名,返回类型别名最原始类型的类型idprintln(field.attrs) //字段的属性注解println(field.is_pub) //字段是否为pubprintln(field.is_mut) //字段是否为mutprintln(field.is_shared) //字段是否为shareprintln(field.is_atomic) //字段是否为atomicprintln(field.is_option) //字段是否为可选字段,带?println(field.is_array) //字段是否为数组println(field.is_map) //字段是否为字典println(field.is_chan) //字段是否为chan类型println(field.is_struct) //字段是否为结构体类型println(field.is_alias) //字段是否为类型别名println(field.is_enum) //字段是否为枚举类型println(field.indirections) //字段是否为指针类型,且是几级指针:0表示非指针,1表示一级指针,2表示2级指针...println('---') }}
可获取的字段的信息,查看vlib/builtin.v源文件中的FieldData结构体:
pubstructFieldData {pub: name string// the name of the field f typ int// the internal TypeID of the field f, unaliased_typ int// if f's type was an alias of int, this will be TypeID(int)// attrs []string// the attributes of the field f is_pub bool// f is in a `pub:` section is_mut bool// f is in a `mut:` section// is_shared bool// `f shared Abc` is_atomic bool// `f atomic int` , TODO is_optional bool// `f ?string` , TODO// is_array bool// `f []string` , TODO is_map bool// `f map[string]int` , TODO is_chan bool// `f chan int` , TODO is_struct bool// `f Abc` where Abc is a struct , TODO is_alias bool// `f MyInt` where `type MyInt = int`, TODO// indirections u8// 0 for `f int`, 1 for `f &int`, 2 for `f &&int` , TODO}
获取结构体选项类型字段值
structFixedStruct { a int b string c ?int d ?string}structEncoder {}fnmain() { fixed := FixedStruct{123,'456',789,'321'}println(fixed.a.str())println(fixed.c?.str()) //返回选项类型字段的值println(fixed.b.int())println(fixed.d?.int()) //返回选项类型字段的值 e := Encoder{} e.encode_struct(fixed)}fn (e &Encoder) encode_struct[T](val T) { $for field in T.fields {mut value := val.$(field.name) //动态获取结构体字段的值$if field.is_option {println('>> ${value ?.str()}') //动态输出结构体选项字段的值println(val.$(field.name) ?.str()) //动态输出结构体选项字段的值 } }}
module mainfnkind[T]() {$if T is $int {println('int') }$if T is $float {println('float') }$if T is $array {println('array') }$if T is $map {println('map') }$if T is $struct {println('struct') }$if T is $interface {println('interface') }$if T is $enum {println('enum') }$if T is $sumtype {println('sumtype') }$if T is $function {println('function') }$if T is $alias {println('alias') }$if T is $option {println('option') }}fnkind_detail[T]() {$if T is u8 {println('u8') }$if T is int {println('int') }$if T is?int {println('?int') }// $if T is !int {// println('!int')// }$if T in [u8,int] {println('u8 or int') }$if T !in [u8,int] {println('not u8 or int') }$if T in [int, $int] {println('int or Int') }$if T in [$sumtype, $map] {println('Sumtype or Map') }$if T in [Abc, Def] {println('Abc or Def') }}structAbc {}interface Def {}enum Xyz { x y z}typeSumtype= Abc |f32|intstructGenericStruct[T] { x T}pub fn (s GenericStruct[T]) m() {$if T is $int {println('Int in method') }$if T is $array {println('Array in method') } $else {println('other') }}fnmain() {// int kind[i8]() kind[i16]() kind[int]() kind[i64]()// int kind[u8]() kind[u16]() kind[u32]() kind[u64]()// float kind[f32]() kind[f64]()// array kind[[]int]()// map kind[map[string]string]()// struct kind[Abc]()// interface kind[Def]()// enum kind[Xyz]()// sumtype kind[Sumtype]()// generic struct s1 := GenericStruct[int]{} s1.m() s2 := GenericStruct[[]string]{} s2.m() s3 := GenericStruct[f32]{} s3.m() kind_detail[Abc]()}