函数
函数定义
使用fn关键字定义函数:
fn main() {
println(add(77, 33))
println(sub(100, 50))
}
fn add(x int, y int) int {
return x + y
}
fn sub(x int, y int) int {
return x - y
}V语言的函数定义(函数签名)基本跟go一样,去除各种视觉干扰的符号,简洁清晰,而函数关键字是跟rust一样的fn,更简洁。
函数的命名强制采用rust一样的小蛇式风格(lower snake case),即小写+下划线的风格,看着很舒服,而不是采用go的大小写来区分可访问性,这样就不会强制要大小写。
主函数
程序从主函数开始运行,主函数的签名中没有参数,也没有返回值,简单干净。
从命令行启动程序时,传递给程序的参数会统一存放在os.args这个字符串数组中,只读,全局可以访问。
主函数如果中途要退出,使用exit(code int)内置函数,并返回错误码给操作系统。
函数访问控制
函数默认模块内部访问,使用pub才可以被模块外部访问。
函数参数
函数的参数采用的是类型后置,相同类型的相邻参数不可以合并类型。
函数的参数默认是不可变的,如果在函数内部要改变传进来的参数,要在函数参数的定义和调用中都要加上mut。
不确定个数参数也是支持的,不确定参数要放在参数的最后一个。
数组可以传递给不确定参数函数,不确定参数函数之间也可以传递参数。
不确定个数参数的类型也可以是指针类型:
函数返回值
函数的返回值可以是单返回值,也可以是多返回值。
因为有了这个特性,其他语言中有的元组类型Tuple,在V语言中就不太需要了。
返回值也可以返回指针类型:
跟go一样,可以使用下划线来忽略函数的某个返回值。
函数defer语句
在函数退出前执行defer代码块,一般用来在函数执行完毕后,释放资源的占用。一个函数可以有多个defer代码块,采用后定义先执行(后进先出LIFO)的原则。
同时,在defer代码块内有一些特殊的注意事项:
defer代码块内不可调用return
defer代码块内不可嵌套定义defer代码块
defer代码块内调用函数时,不可向上抛转错误,例如 a=test1() ?
执行结果:
可以使用$res()函数,在defer语句中取得函数的返回值:
函数类型
相同的函数签名表示同一类函数,可以用type定义为函数类型。
函数作为参数
函数作为返回值
闭包的参数传递
函数支持闭包,上级函数和闭包函数是两个单独的作用域,要将上级函数中的变量要传递给闭包函数,需要用[中括号]特别列出来,这样闭包函数内才可以正常使用上级函数的变量。
如果要传递的是变量的引用也可以,不过要确保变量在调用函数的时候始终可用,否则就会产生错误。
lambda表达式
支持简写的lambda表达式,类似于匿名函数,竖线中间是函数的参数,不用标识类型,后面带一个表达式作为函数的返回值:
函数递归
函数支持递归调用:
泛型函数
函数支持泛型,参考泛型章节。
函数重载
V语言不支持函数重载,同一个函数名,在模块中只能有一个,即使是参数不一样。
以下代码无法通过编译:
函数参数默认值
函数的参数没有默认值这个特性。不过可以使用结构体参数来实现同样的效果。
函数命名参数
可以使用结构体作为参数,实现命名参数的效果,这个方式比语言上直接实现多了一个步骤,就是要先创建一个结构体参数。
函数使用结构体作为参数,参数的传递只根据参数名来匹配,跟参数的顺序无关。
这个语法在ui模块比较常用到,用来让函数的参数可读性更好。
结构体参数
使用结构体作为函数的参数,并且结构体使用了[params]注解,就可以实现参数的默认值和命名参数传参的效果。
结构体参数加了[params]注解,函数的参数可以什么都不传,直接使用结构体字段的默认值,如果结构体字段没有特别指定默认值,默认就是零值初始化。
内联函数
可以对函数添加[inline]注解,主要的用途是在调用C代码库的时候使用最多,内联函数跟C的内联函数概念一样,生成的也是C的内联函数。
详细参考:调用C代码库。
匿名/内部函数
可以在函数内部定义匿名函数:
函数注解
@[deprecated]
模块发布给其他用户使用后,如果模块的某个函数想要声明作废或者被代替,可以使用作废注解。
@[inline]
inline注解的功能跟C函数的inline函数一样。
@[unsafe]
参考不安全代码章节。
@[trusted]
参考不安全代码章节。
@[live]
代码热更新功能,只对函数内的代码热更新生效,改变结构体是不行的。实际生产用处不大,开发时可以使用,像脚本语言那样,保存即生效,不用重新运行程序。v watch run . 也有类似效果,差别是watch实际上是自动监控文件变化,自动重新运行程序。
运行时也需要加上-live选项,才会有效果。
@[export]
一般来说V函数编译生成C代码时,C函数名会自动变为[模块名+双下划线+函数名],比如在main模块中的add函数会变为main__add。
使用export注解可以自定义V函数生成的C函数名称,一般用于C函数中调用V函数时,可直接使用export中自定义的函数名。
生成的C代码:
实际上的实现方式是除了生成默认的main__add函数外,又生成了一个export注解设置的C函数。
@[weak]
weak注解目前只支持函数函数和全局变量,weak注解告诉C编译器,该函数或全局变量是一个弱类型的,跟其他C代码一起编译时,在链接的时候,如果编译生成的C代码中存在一个同名的函数或全局变量(强类型的),则使用这个强类型的,链接器不会报重复定义的错误。目前看这个注解大部分的情况用在c2v的代码中,而且一般跟[export]注解一起使用,一般的V代码很少用到这种场景。
@[if xxx平台]
如果函数加上这个注解,只有在对应的平台上才编译生成这个函数,其他平台不会生成,函数的调用也会忽略。
内置函数
V在内置模块builtin中,内置了一些函数,可以全局使用,所有的内置函数可以在vlib/builtin目录中找到定义:
dump函数
跟C语言中的dump函数功能一样:把某个表达式的数据转储,并输出,dump函数主要用于调试,比println函数更为方便,清晰。
表达式被调用了几次,每次的结果如何,代码的位置,都会被清楚地打印出来。
输出:
最后更新于
这有帮助吗?