函数
- 介绍函数的分类及调用。
- 介绍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;
}
匿名函数
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);
.型函数调用
.型函数调用主要用途是调用外部函数或者调用某个本域内的object的函数,比如:
// 调用外部函数
float val = math.abs(-3.14); // 使用math中的abs()函数,求绝对值
// 调用本域的object函数
// obj.gs
public void print_hello_world()
{
write("hello world");
}
// test.gs
object obj = load_static("obj.gs", this_domain());
obj.print_hello_world();
.?型函数调用
用法类似于.型函数调用,后面加个'?'表示这个调用可能是空的调用。
如果有调用的话,它就相当于.型调用,否则它啥事也不干,也不会报错,相当于没有这条语句。
该调用设计的主要目的是为了满足使用者在不清楚一个函数存不存在的时候减少判断,方便书写。
举个例子:
// obj.gs
public void print_hello_world()
{
write("hello world");
}
// test.gs
object obj = load_static("obj.gs", this_domain());
obj.print_hello_world(); // 相当于.型调用
obj.?if_exist_function(); // 不调用也不报错,相当于没有这条语句
与该调用方式类似的是?.型调用和?.?型调用。 ?.调用: 如果调用的object不存在,不会报错,相当于没有该语句。如果存在的话相当于.调用。 ?.?调用:如果调用的object不存在或者是空的调用,不会报错,相当于没有该语句。否则相当于.调用。