函数
- 介绍函数的分类及调用。
- 介绍gs中函数式的用法。
备注
TODO : 介绍一下override
函数调用
函数(Function)实际上就是一种方法,每个函数都有其特定的功能,而Function就是实现这个功能的方法。
外部函数和内部函数
GS中的函数主要分成两种:外部函数和内部函数,它们的区别是;
- 最主要区别是外部函数是GS底层实现的函数,而内部函数则是使用GS来实现的函数;
- 内部函数可以依赖于外部函数取实现,外部函数可以实现一些内部函数 无法实现的功能,比如printf()等;
- 外部函数的作用域是整个源程序,而内部函数只能在它的域中使用或者跨域调用。
普通函数
GS的普通函数定义基本语法为:
prefix return_type function_name ( argument_list )
{
// body_of_general_function
}
普通函数语法定义解释:
-
prefix表示类型前缀,它是可选的,默认为private,其类型有以下五种:
- public(公有)
- protected(保护)
- private(私有) -> 默认
- virtual(虚拟)
- override(覆盖)
-
return_type表示返回值类型,也就是这个函数执行完之后需要返回值的类型
- return_type的类型是mixed,所有已有数据类型或者自定义数据类型都可以作为return_type
- return_type是每个函数必须要有的,不可省略
- 如果函数没有返回值,可以标注为
void
-
function_name是函数的名字
- 它也是不可省略的
- 不能跟系统函数取同一个名字,以免造成冲突
-
argument_list表示函数的参数
- 函数的参数可以是零个或多个
- 参数表中参数的格式为value_type value,其中参数之间用逗号隔开
- 使用
...可以接受变长参数
-
body_of_general_function是函数体
- 函数体是实现函数的最主要模块
- 如果函数有返回值则需要在每个函数可能运行结束的最后return一个return_type类型的值
举个函数定义的例子:
public int max_int(int x, int y) // 计算x和y中的最大值,函数定义为公有函数
{
if(x > y)
return x;
return y;
}
受限定的函数参数
函数参数可以使用修饰符进行限制,目前支持的修饰符包括:
| 受支持的修饰符 | 目的 | 限制 |
|---|---|---|
readonly | 限定参数只能是 readonly 的实例 | 不能用于 int, float, handle 等不能为 readonly 的类型,也不能修饰 mixed 类型;函数内不能对被修饰为 readonly 的参数进行赋值操作 |
parallel | 限定参数只能是 parallel 的实例 | 不能用于 int, float, handle 等不能为 parallel 的类型,也不能修饰 mixed 类型;函数内不能对被修饰为 parallel 的参数进行赋值操作 |
当参数被使用 readonly 或 parallel 修饰后,如果传入的实参并未按预期地生效,则抛出异常:
void foo(readonly map m)
{
// ...
}
foo({}); // 运行时异常,传入的参数并不是 readonly 的
foo(make_parallel({})); // 运行时异常,readonly 的参数只接受 readonly, 反之也一样
foo(make_readonly({})); // Ok
匿名函数
GS中有一种函数叫做匿名函数,它存在的意义在于有时候我们需要在定义一个全局变量,但是GS语言没有static方法, 通过匿名函数,可以将匿名函数使用的变量存储在堆里面,以此可以实现全局变量的声明运用。
GS的匿名函数定义基本语法为:
function [ capture ]( argument_list )
{
// body_of_delegate_function
};
匿名函数语法定义解释:
-
capture表示捕获的外部变量
- 决定了使用外部变量时按值捕获还是按引用捕获:
[&]用到的任何外部变量都按引用捕获[&x]变量x按引用捕获,其他变量按值捕获,可以指示多个引用捕获项
- 如果不需要指示引用捕获,可以省略
[]
- 决定了使用外部变量时按值捕获还是按引用捕获:
-
argument_list表示函数的形参列表,规则和普通函数的形参列表一致
- 与C++不同的是,GS不允许省略空的形参列表:
()
- 与C++不同的是,GS不允许省略空的形参列表:
-
body_of_delegate_function是函数体
- 函数体是实现函数的最主要模块
- 如果函数有返回值则需要在每个函数可能运行结束的最后return一个值
举个例子:
function test()
{
int i = 0;
i++;
printf("in i = %d\n", i); // 输出 in i = 1
function fun = [&]() // 定义匿名函数,返回i
{
i++;
return i;
// printf("i = %d\n", i);
};
return fun;
}
function fun = test();
printf("out i = %d\n", fun.call_local()); // 输出 out i = 2
printf("out i = %d\n", fun.call_local()); // 输出 out i = 3
多种返回值类型函数
GS函数提供多种返回值类型,比如:
array arr = [1, 2, nil, "Three", 2]; // 初始化array
mixed get_item(int index) // 使用mixed作为返回值类型
{
return arr[index];
}
mixed val = get_item(1); // val = 2
val = get_item(2); // val = nil
val = get_item(3); // val = "Three"
变长参数列表
GS函数提供变长参数列表,在函数参数列表中使用三点(...)表示函数有可变的参数。
public array ping_args(...)
{
if($?) // 如果有参数
{
if(lengthof($<) == 1) // 如果只有一个参数
return [$1]; // 返回第一个参数
return ($<)[0..<1]; // 否则返回所有参数
}
else // 没有参数
return ["no argument"];
}
$ 相关参数介绍:
$<表示所有参数列表$?表示是否有参数$num表示第num个参数,如$1表示第一个参数($<)[begin_num..<end_num]从第begin_num个参数(第一个为0)开始到倒数第end_num个(包括)。比如($<)[0..<1]表示所有参数。
函数调用类型
GS的函数调用类型主要分成以下几类。
直接函数调用
直接函数调用有两种情况,一种是外部函数调用,另外一种则是同一个文件内定义的或者#include进来的函数。比如:
// 系统函数调用
lengthof("Hello world");
get_system_info();
// 同一文件函数调用,(其实"#include xxx"是把xxx文件代替"#include xxx"这条语句,
// 实际上也算是同一文件内的函数。
int max(int x, int y)
{
return x > y ? x : y;
}
int x = 1, y = 2;
int ans = max(x, y);