有别于运行时代码,不管是那个平台的代码都会生成对应的C代码.

    在V语言中所有的编译时代码都是以$开头的.

    $for用来实现反射的效果,目前只实现了结构体的反射,可以在运行时获得某一个结构体所有字段和方法的信息

    遍历结构体方法,返回方法信息数组:[]FunctionData

    1. name: 'int_method1' //方法名称
    2. attrs: [] //方法注解
    3. args: [] //方法参数
    4. return_type: 7 //方法返回类型
    5. typ: 0 //未知
    6. }
    1. struct App {
    2. a string
    3. b string
    4. mut:
    5. c int
    6. d f32
    7. pub:
    8. e f32
    9. f u64
    10. pub mut:
    11. g string
    12. h byte
    13. }
    14. ['foo/bar/three']
    15. fn (mut app App) run() {
    16. }
    17. ['attr2']
    18. fn (mut app App) method2() {
    19. }
    20. fn (mut app App) int_method1() int {
    21. return 0
    22. }
    23. fn (mut app App) int_method2() int {
    24. return 1
    25. }
    26. fn (mut app App) string_arg(x string) {
    27. }
    28. fn no_lines(s string) string {
    29. return s.replace('\n', ' ')
    30. }
    31. fn f1() {
    32. println(@FN)
    33. $for method in App.methods { //遍历结构体所有方法
    34. println(' method: $method.name | ' + no_lines('$method'))
    35. assert method.name in methods
    36. }
    37. }
    38. fn f2() {
    39. println(@FN)
    40. $for method in App.methods { //遍历结构体所有方法
    41. println(' method: ' + no_lines('$method'))
    42. $if method.typ is fn () {
    43. assert method.name in ['run', 'method2']
    44. }
    45. $if method.return_type is int {
    46. assert method.name in ['int_method1', 'int_method2']
    47. }
    48. $if method.args[0].typ is string {
    49. assert method.name == 'string_arg'
    50. }
    51. }
    52. }
    53. fn main() {
    54. println(@FN)
    55. $for field in App.fields { //遍历结构体所有字段
    56. println(' field: $field.name | ' + no_lines('$field'))
    57. $if field.typ is string {
    58. assert field.name in ['a', 'b', 'g']
    59. }
    60. $if field.typ is f32 {
    61. assert field.name in ['d', 'e']
    62. }
    63. if field.is_mut {
    64. assert field.name in ['c', 'd', 'g', 'h']
    65. }
    66. if field.is_pub {
    67. assert field.name in ['e', 'f', 'g', 'h']
    68. }
    69. if field.is_pub && field.is_mut {
    70. assert field.name in ['g', 'h']
    71. }
    72. }
    73. f1()
    74. f2()
    75. }

    动态字段赋值

    1. struct TestStruct {}
    2. fn (t TestStruct) one_arg(a string) {
    3. println(a)
    4. }
    5. fn (t TestStruct) two_args(a string, b int) {
    6. println('$a:$b')
    7. fn main() {
    8. t := TestStruct{}
    9. if method.name == 'two_args' {
    10. t.$method('hello', 42) // 动态调用方法
    11. }
    12. }
    13. }
    1. struct MyStruct {}
    2. struct TestStruct {}
    3. fn (t TestStruct) three_args(m MyStruct, arg1 string, arg2 int) {
    4. println('$arg1,$arg2')
    5. }
    6. fn main() {
    7. t := TestStruct{}
    8. m := MyStruct{}
    9. args := ['one' '2'] //数组参数
    10. $for method in TestStruct.methods {
    11. if method.name == 'three_args' {
    12. t.$method(m, args) //动态调用方法时,也可以传递一个数组,会自动解构展开
    13. }
    14. }
    15. }

    编译时预置的全局变量

    可以使用$env函数获取环境变量

    运行时代码中os.get_env函数也可以实现相同的效果

    1. module main
    2. //可以在C宏语句中使用,让C宏的定义更灵活
    3. #flag linux -I $env('JAVA_HOME')/include
    4. fn main() {
    5. compile_time_env := $env('PATH')
    6. println(compile_time_env)
    7. }

    编译时嵌入文件

    可以使用$embed_file编译时函数,把各种类型的文件在编译时嵌入到二进制文件中,更方便编译打包成单一可执行文件,方便部署,目前vweb框架中有使用到.

    1. module main
    2. import os
    3. fn main() {
    4. mut embedded_file := $embed_file('v.png')
    5. mut fw := os.create('exported.png') or { panic(err) }
    6. fw.write_bytes(embedded_file.data(), embedded_file.len)
    7. fw.close()
    8. }

    V内置了一个简单的txt和html模板,可以通过$tmpl编译时函数,进行渲染

    1.txt模板文件内容

    1. name: @name //@开头的都是模板文件中需要替换的同名变量
    2. age: @age
    3. numbers: @numbers
    4. @for number in numbers //也可以遍历数组类型变量
    5. @end