函数

函数定义

使用fn关键字定义函数

  1. fn main() {
  2. println(add(77, 33))
  3. println(sub(100, 50))
  4. }
  5. fn add(x int, y int) int {
  6. return x + y
  7. }
  8. fn sub(x int, y int) int {
  9. return x - y
  10. }

V语言的函数定义(函数签名)基本跟go一样

去除各种视觉干扰的符号,简洁清晰,而函数关键字是跟rust一样的fn,更简洁

函数的命名强制采用rust一样的小蛇式风格(lower snake case),即小写+下划线的风格,看着很舒服,而不是采用go的大小写来区分可访问性,这样就不会强制要大小写

函数访问控制

默认模块内部访问,使用pub才可以被模块外部访问

  1. module mymodule
  2. fn private_fn() { // 模块内部可以访问,模块外部不可以访问
  3. }
  4. pub fn public_fn() { // 模块内部和外部都可以访问
  5. }

函数参数

函数的参数采用的是类型后置,相同类型的相邻参数可以合并类型

函数的参数默认是不可变的,如果在函数内部要改变传进来的参数,要在函数参数的定义和调用中加上mut

  1. fn my_fn(mut arr []int) { // 1.参数定义也要是可变的
  2. for i := 0; i < arr.len; i++ {
  3. arr[i] *= 2
  4. }
  5. }
  6. fn main() {
  7. mut nums := [1, 2, 3] // 2.传进来的参数要是可变的
  8. my_fn(mut nums) // 3.调用函数时,还需要在参数前加上mut,不然会报错
  9. println(nums) // 返回[2, 4, 6],函数执行后,传进来的参数被改变了
  10. }

不确定个数参数也是支持的,不确定参数要放在参数的最后一个

  1. fn my_fn(i int, s string, others ...string) {
  2. println(i)
  3. println(s)
  4. println(others[0])
  5. println(others[1])
  6. println(others[2])
  7. }
  8. fn main() {
  9. my_fn(1, 'abc', 'de', 'fg', 'hi')
  10. }

数组可以传递给不确定参数函数,不确定参数函数之间也可以传递参数

  1. module main
  2. fn main() {
  3. a := ['a', 'b', 'c']
  4. println(variadic_fn_a(...a)) //数组解构赋值后,传递给不确定参数数组
  5. }
  6. fn variadic_fn_a(a ...string) string {
  7. return variadic_fn_b(...a) //数组解构赋值后,传递给不确定参数数组
  8. }
  9. fn variadic_fn_b(a ...string) string {
  10. a0 := a[0]
  11. a1 := a[1]
  12. a2 := a[2]
  13. return '$a0$a1$a2'
  14. }

函数返回值

函数的返回值可以是单返回值,也可以是多返回值

  1. fn bar() int { //单返回值
  2. return 2
  3. }
  4. fn foo() (int, int) { //多返回值
  5. return 2, 3
  6. }
  7. fn some_multiret_fn(a int, b int) (int, int) {
  8. return a + 1, b + 1 //可以返回表达式
  9. }
  10. fn main() {
  11. a, b := foo()
  12. println(a) // 2
  13. println(b) // 3
  14. }

返回值也可以返回指针类型

  1. fn get_the_dao_way() voidptr { //返回通用指针
  2. return voidptr(0)
  3. }
  4. fn multi_voidptr_ret() (voidptr, bool) { //返回通用指针
  5. return voidptr(0), true
  6. }
  7. fn multi_&byte_ret() (&byte, bool) { //返回字节指针
  8. return &byte(0), true
  9. }

忽略返回值

跟go一样,可以使用下划线来忽略函数的某个返回值

  1. fn main() {
  2. a, _ := foo() // 忽略第二个返回值
  3. _, _ := foo() // 也可以忽略全部的返回值
  4. println(a) // 2
  5. b := bar()
  6. _ := bar()
  7. println(b) // 2
  8. }
  9. fn bar() int {
  10. return 2
  11. }
  12. fn foo() (int, int) {
  13. return 2, 3
  14. }

函数defer语句

在函数退出前执行defer代码块,一般用来在函数执行完毕后,释放资源的占用.

一个函数可以有多个defer代码块,采用后定义先执行(后进先出)的原则.

同时在defer代码块内有一些特殊的注意事项:

  • defer代码块内不可调用return
  • defer代码块内不可嵌套定义defer代码块
  • defer代码块内调用函数时,不可向上抛转错误,例如 a=test1() ?
  1. fn main() {
  2. println('main start')
  3. // defer {defer_fn1()} //写成单行也可以
  4. // defer {defer_fn2()}
  5. defer {
  6. defer_fn1()
  7. }
  8. defer {
  9. defer_fn2()
  10. }
  11. println('main end')
  12. }
  13. fn defer_fn1() {
  14. println('from defer_fn1')
  15. }
  16. fn defer_fn2() {
  17. println('from defer_fn2')
  18. }

执行结果:

  1. main start
  2. main end
  3. from defer_fn2
  4. from defer_fn1

函数类型

相同的函数签名,表示同一类函数,可以用type定义为函数类型

  1. type Mid_fn = fn (int, string) int

函数作为参数

  1. fn sqr(n int) int {
  2. return n * n
  3. }
  4. fn run(value int, op fn (int) int) int {
  5. return op(value)
  6. }
  7. fn main() {
  8. println(run(5, sqr)) // "25" sql函数作为参数传递
  9. }

函数作为返回值

  1. module main
  2. fn add(x int) int {
  3. return x
  4. }
  5. fn sum() fn (int) int { // 函数类型作为返回值
  6. return add
  7. }
  8. fn main() {
  9. a := sum()
  10. println(a(2))
  11. }

函数递归

函数也是可以递归调用的

泛型函数

参考泛型章节

函数重载

V不会有函数重载

函数默认值

函数的参数目前还没有参数默认值这个特性

内联函数

可以对函数添加[inline]注解,主要的用途是在调用C代码库的时候使用最多,内联函数跟C的内联函数概念一样,生成的也是C的内联函数

  1. [inline]
  2. pub fn width() int {
  3. return C.sapp_width()
  4. }

详细参考:调用C代码库

匿名/内部函数

可以在函数内部定义匿名函数:

  1. import sync
  2. fn main() {
  3. f1 := fn (a int) { // 定义函数类型变量
  4. println('hello from f1')
  5. }
  6. f1(1)
  7. f2 := fn (a int) { // 定义函数类型变量
  8. println('hello from f2')
  9. }
  10. f2(1)
  11. fn (a int) { // 匿名函数定义同时调用
  12. println('hello from anon_fn')
  13. }(1)
  14. // 匿名函数结合go使用
  15. mut wg := sync.new_waitgroup()
  16. go fn (mut wg sync.WaitGroup) {
  17. println('hello from go')
  18. wg.done()
  19. }(mut wg)
  20. wg.wait()
  21. }

函数注解

deprecated

模块发布给其他用户使用后,如果模块的某个函数想要声明作废,可以使用作废注解

  1. [deprecated] //函数作废注解
  2. pub fn ext(path string) string {
  3. panic('Use `filepath.ext` instead of `os.ext`') //结合panic进行报错提示
  4. }
  5. [deprecated:'可以在这里写说明'] //带说明的作废注解,编译器提示函数作废的时候会显示出来
  6. pub fn (p Point) position() (int, int) {
  7. return p.x, p.y
  8. }
  9. [deprecated:'这是作废说明']
  10. [deprecated_after: '2021-03-01'] //在某个日期后开始作废,一定要放在deprecated后,才会警告
  11. pub fn fn1() (int, int) (int, int) {
  12. return p.x, p.y
  13. }
  14. //函数被调用,就会出现如下警告:
  15. //warning: function `fn1` has been deprecated since 2021-03-01; 这是作废说明

inline

inline注解的功能跟C函数的inline函数一样

  1. [inline] //函数inline注解
  2. pub fn sum(x y int) int {
  3. return x+y
  4. }
  5. [inline] //方法inline注解
  6. pub fn (p Point) position() (int, int) {
  7. return p.x, p.y
  8. }

unsafe

参考不安全代码章节

trusted

参考不安全代码章节

live

代码热更新功能,实际生产用处不大

开发时可以使用,像脚本语言那样,保存即生效,不用重启服务器,正式发布的时候还是要去除live注解,有些麻烦

  1. module main
  2. import time
  3. [live]
  4. fn print_message() {
  5. println('更新时间:${time.now()}')
  6. println('该函数范围内的代码修改后,不需要重新编译运行,保存即生效')
  7. }
  8. fn main() {
  9. for {
  10. print_message()
  11. time.sleep(1*time.second)
  12. }
  13. }

运行时也需要加上-live选项,才会有效果

  1. v -live run main.v

内置函数

V内置了一些函数,可以全局使用

dump函数

跟C语言中的dump函数功能一样,把某个表达式的数据转储,并输出

dump函数主要用于调试,比println函数更为方便,清晰

表达式被调用了几次,每次的结果如何,代码的位置,都会被清楚地打印出来

  1. fn factorial(n u32) u32 {
  2. if dump(n <= 1) {
  3. return dump(1)
  4. }
  5. return dump(n * factorial(n - 1))
  6. }
  7. fn main() {
  8. println(factorial(5))
  9. }

输出:

  1. [xxx/main.v:2] n <= 1: false
  2. [xxx/main.v:2] n <= 1: false
  3. [xxx/main.v:2] n <= 1: false
  4. [xxx/main.v:2] n <= 1: false
  5. [xxx/main.v:2] n <= 1: true
  6. [xxx/main.v:3] 1: 1
  7. [xxx/main.v:5] n * factorial(n - 1): 2
  8. [xxx/main.v:5] n * factorial(n - 1): 6
  9. [xxx/main.v:5] n * factorial(n - 1): 24
  10. [xxx/main.v:5] n * factorial(n - 1): 120