和普通变量声明类似,函数参数类似于多个普通变量声明。
参数形式
- 大部分编程语言的函数参数放在函数名紧随的圆括号里,不同参数用逗号分隔。
C/ObjC/C++/Java/C#/Kotlin/Python/仓颉 等均是此。
参数列表和逗号表达式
函数参数列表虽然以逗号分隔,但不是逗号表达式。即,函数参数里面的逗号一定不是逗号运算符,而是函数参数分隔。如果一定需要在函数参数用逗号表达式,用括号括起来。
声明和调用类型不一致
- C语言函数有声明和定义两种形态,在某些情况,可能出现函数声明晚于函数调用,编译器没法知道真实的参数类型,会执行默认的类型转换。
- 例如先调用func(1.2),再定义void func(float f),编译器会认为调用时传入的是double类型变量1.2,但实际执行参数是float,结果不如预期。
- Java/C#/Python不存在这种情况,编译器或解释器提前会获取类型信息而不是延迟到调用时。
一些独特的函数参数形式
- 经典C语言将函数参数单独声明,类似 int f(a, b) float a, b; … 这种写法已被摒弃。
- ObjC函数参数形式与众不同,实参前会加前缀,尤其参数很多的情况,可读性很强。例如:
[person setAge: 29 setSex:1 setClass: 35]; 如果是C++代码,参数很多,有时会记不清参数位置。
当然,也可以对第二个之后的参数不加前缀,形如: [person setAge: 29 :1 : 35]; - C# 4.0引入了具名参数,参数可以加前缀,增强可读性。
- Kotlin 支持具名参数,支持形如:形参1 = 实参1 这种形式。
show(name = "Alex", age = 29); - Python 提供的方式和Kotlin类似,被称为关键字实参,例如:
函数原型:def show(name, age)
调用方式:show(age = 29, name = "Alex"); - 仓颉 也支持命名参数,是参数后面加上"!",例如:
func add(a!: Int64, b!: Int64) : Int64, 函数调用必须加上命名参数名:add(a: 1, b: 2).- 值得注意的是,仓颉支持一个函数的命名参数和非命名参数同时存在。
形参和实参
- 形式参数和实际参数不必要同名,C语言可以从汇编代码看到,名字其实是地址或寄存器的代名词,和代码中的名字无任何关系。
- Parameter和Argument都是参数,在很多场景二者没区别。Wiki的说法是parameter表示形参,argument表示实参,这有点学院派了,仁者见仁智者见智。
隐式类型转换
- 实参类型可以隐式转换成形参,编译器才不会报错。
参数默认值
- C/ObjC 不支持默认参数。
- C++/Java/C#/Python/PHP/仓颉 等均支持函数参数默认值,一般而言,默认值参数必须放在最后。
- Kotlin 默认参数不一定放在最后,它通过具名参数显式指定参数。
函数参数和局部变量
大部分编程语言不太区别对待函数参数和局部变量,都统一当做函数"局部"变量,它们不能重名。但也有例外。
- 仓颉 为了更安全,函数参数默认是不可修改的变量,只能读不能写。
函数作为参数
- C/ObjC/C++/仓颉 等编程语言都支持函数作为参数。
- 对于支持Lambda表达式的一些编程语言,Lambda也可以单做函数作为参数。比如仓颉。