函数

函数是基本的代码块, 用于执行一个任务.

你可以通过函数来划分不同功能, 逻辑上每个函数执行的是指定的任务.

Z1h 语言标准库提供了多种可动用的内置的函数. 例如, len() 函数可以接受不同类型参数并返回该类型的长度. 如果我们传入的是字符串则返回字符串的长度, 如果传入的是数组, 则返回数组中包含的元素个数.

函数定义

函数定义格式如下

函数名 = 参数 => {
    函数体
}

函数名 = (参数1, 参数2...) => {
    函数体
}

func 函数名(参数1, 参数2...) { // 这种情况只能声明局部的函数
    函数体
}

也可以将形参的内容解出, 如

// 将第一个参数的key1、key2值解出
函数名 = ({key1, key2}, 参数2) => {
    函数体
}

// 将第一个参数(数组)的key1、key2值解出
函数名 = ([item1, item2], 参数2) => {
    函数体
}

示例

add1 = num => {
    return num + 1
}

add = (num1, num2) => num1 + num2

func minus(num1, num2) {
    return num1 - num2
}

hello = {name, age} => {
    printf('Hello, name = %v, age = %v', name, age)
}

hi = ([p1, p2], a2) => {
    printf({p1, p2, a2})
}

定义解析

名称 描述
func 函数由 func 开始声明
函数名称 函数名就是这个函数的变量名
参数列表 参数就像一个占位符, 当函数被调用时, 你可以将值传递给参数, 这个值被称为实际参数. 参数列表指定的是参数类型、顺序、及参数个数. 参数是可选的, 也就是说函数也可以不包含参数.
函数体 函数定义的代码集合.

函数调用

当创建函数时, 你定义了函数需要做什么, 通过调用该函数来执行指定任务.

调用函数, 向函数传递参数, 并返回值, 例如:

func getDouble(num) {
    return num * 2;
}

getDouble(100);
// 输出200

函数返回多个值

Z1h 函数可以返回多个值, 调用得到的值是一个数组, 例如:

func nameAndSuffix(str) {
    var suffix = $file.ext(str, '');
    return (suffix ? str[:suffix.length+1]: str), suffix;
}

print(nameAndSuffix("hello.z1h"));
// 输出[ "hello", ".z1h" ]

[foo, bar] = nameAndSuffix('index.html');
print(`${foo} and ${bar}`)

示例

add = e => {
    e + 1
}
print(add(3))



plus = (num1, num2) => {
    num1 + num2
}
print(plus(3, 7))



func minus(n1, n2) {
    n1 - (n2 || 0)
}
minus(8, 7)

自动关闭的对象

如果一个对象包含Close函数(包括自定义结构体/map/原生对象), 可以使用该函数自动关闭

这个使用方式与Python很相似

// os.Create 返回的是 *os.File 类型, 包含Close函数
with assert(os.Create(`test.txt`)) as f {
    assert(f.Write("你好啊".bytes))
}

或者

with {
    tag: '测试',
    Close: e=>{print(`关闭: 标记=${this.tag}, 名称=${this.name}`)},
} as obj {
    obj.name = "haha"
    print('设置了name')
}

逃逸对象(闭包)

如果你的函数返回了函数(或函数的某种形式的引用), 包含了上层定义的变量, 此时就需要进行变量的逃逸 (相当于js里的闭包概念)

Z1h也是支持逃逸(闭包)的, 在产生函数的时候会保存当前的栈环境, 示例代码如下:

// 声明一个函数, 这个函数返回了三个函数
f = e => {
    var i = 1 // 三个函数共用的变量
    return [
        e => { i++ },
        e => { i += 2 },
        e => { i = nil; print('I=' + i) },
    ]
};
// 获取一套函数
[f1, f2, f3] = f()

// 以下函数逐行调用, 并观察结果
f1()
f2()
f3()
f2()
f1()
print(i) // 报错: 没有i这个变量

与Go原生交互

如果一个函数需要转成Go的原生函数, 只需要使用以下方式即可创建:

f = (e=>`传入参数的平方为${e*e}`).native_int_return_string
// 后面的部分也可以简写成 .native_i_return_s
print('Go类型:', type(f))
// func(int) string
print('返回结果:', f(20))
// "传入参数的平方为400"

如果需要创建有复杂类型的函数, 可以通过native方法:

f = new('func',
    ['', z1h.ElemType(os.FileInfo.Ptr), z1h.ElemType(errors.Interface)],
    z1h.ElemType(errors.Interface),
    (name, info, err)=>{
        print(`Name: ${name}, Size: ${info.Size()?? 'No info'}`)
        return z1h.NilValue(errors.Interface)
    }
)
print(type(f))
// func(string, os.FileInfo, error) error
path_filepath.Walk(".", f)