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

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

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

    函数访问控制

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

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

    函数参数

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

    函数的参数默认是不可变的,如果在函数内部要改变传进来的参数,要在函数参数的定义和调用中加上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. return voidptr(0)
    2. }
    3. fn multi_voidptr_ret() (voidptr, bool) { //返回通用指针
    4. return voidptr(0), true
    5. }
    6. fn multi_&byte_ret() (&byte, bool) { //返回字节指针
    7. return &byte(0), true
    8. }

    忽略返回值

    函数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. fn main() {
    8. a := sum()
    9. println(a(2))
    10. }

    函数递归

    函数也是可以递归调用的

    泛型函数

    参考

    V不会有函数重载

    函数默认值

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

    内联函数

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

    1. [inline]
    2. pub fn width() int {
    3. }

    详细参考:调用C代码库

    匿名/内部函数

    函数注解

    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