有别于运行时代码,不管是那个平台的代码都会生成对应的C代码.
在V语言中所有的编译时代码都是以$开头的.
$for用来实现反射的效果,目前只实现了结构体的反射,可以在运行时获得某一个结构体所有字段和方法的信息
遍历结构体方法,返回方法信息数组:[]FunctionData
name: 'int_method1' //方法名称
attrs: [] //方法注解
args: [] //方法参数
return_type: 7 //方法返回类型
typ: 0 //未知
}
struct App {
a string
b string
mut:
c int
d f32
pub:
e f32
f u64
pub mut:
g string
h byte
}
['foo/bar/three']
fn (mut app App) run() {
}
['attr2']
fn (mut app App) method2() {
}
fn (mut app App) int_method1() int {
return 0
}
fn (mut app App) int_method2() int {
return 1
}
fn (mut app App) string_arg(x string) {
}
fn no_lines(s string) string {
return s.replace('\n', ' ')
}
fn f1() {
println(@FN)
$for method in App.methods { //遍历结构体所有方法
println(' method: $method.name | ' + no_lines('$method'))
assert method.name in methods
}
}
fn f2() {
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'
}
}
}
fn main() {
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()
}
动态字段赋值
struct TestStruct {}
fn (t TestStruct) one_arg(a string) {
println(a)
}
fn (t TestStruct) two_args(a string, b int) {
println('$a:$b')
fn main() {
t := TestStruct{}
if method.name == 'two_args' {
t.$method('hello', 42) // 动态调用方法
}
}
}
struct MyStruct {}
struct TestStruct {}
fn (t TestStruct) three_args(m MyStruct, arg1 string, arg2 int) {
println('$arg1,$arg2')
}
fn main() {
t := TestStruct{}
m := MyStruct{}
args := ['one' '2'] //数组参数
$for method in TestStruct.methods {
if method.name == 'three_args' {
t.$method(m, args) //动态调用方法时,也可以传递一个数组,会自动解构展开
}
}
}
编译时预置的全局变量
可以使用$env函数获取环境变量
运行时代码中os.get_env函数也可以实现相同的效果
module main
//可以在C宏语句中使用,让C宏的定义更灵活
#flag linux -I $env('JAVA_HOME')/include
fn main() {
compile_time_env := $env('PATH')
println(compile_time_env)
}
编译时嵌入文件
可以使用$embed_file编译时函数,把各种类型的文件在编译时嵌入到二进制文件中,更方便编译打包成单一可执行文件,方便部署,目前vweb框架中有使用到.
module main
import os
fn main() {
mut embedded_file := $embed_file('v.png')
mut fw := os.create('exported.png') or { panic(err) }
fw.write_bytes(embedded_file.data(), embedded_file.len)
fw.close()
}
V内置了一个简单的txt和html模板,可以通过$tmpl编译时函数,进行渲染
1.txt模板文件内容
name: @name //@开头的都是模板文件中需要替换的同名变量
age: @age
numbers: @numbers
@for number in numbers //也可以遍历数组类型变量
@end