函数(Function
)也被称为方法(Method
)。其最直观的理解就是数据中的函数,比如y=f(x)
,在编程中,f
对输入x
进行处理,返回结果y
,就是一个函数。
接受输入,逻辑处理,返回结果。这是一切编程的本质,所有的程序都是这样的处理模型,无非是输入的内容不同,或逻辑处理的规则不同,或返回的表现形式不同,以实现不同的功能或效果。
函数本质上是完成一定功能的代码块,通过将一段代码包装为函数,可以在需要的时候进行调用,完成要想的功能。
比如下面的代码块,用于完成加法的功能,放在了名为add
的函数内,这就是一个完成的函数:
int add(int x, int y){
return x+y;
}
当用到加法功能时,直接调用add
函数即可。
print(add(1,2)); // 输出 3
Dart是一个真正面向对象的语言,所以,即便函数也是对象,其类型为Function
。这就意味着,函数可以和普通的对象(变量数据)一样使用,可以被赋值、可以作为函数参数。
函数的定义
dart中定义一个函数的基本结构如下,如果函数没有返回值,则返回值类型 为 void
:
返回值类型 函数名(参数类型 参数名){
函数体;
}
void
是一种特殊的类型,表示一个值永远不会被使用。
void 常用于声明函数的返回类型,表示没有返回值。
比如,一个计算平方的函数:
int square(int x) {
return x * x;
}
比如,还是上面的加法函数:
int add(int a ,int b ) {
int c = a + b; // 赋值语句
return c; // 返回语句
}
add
为函数名,前面的类型为函数的返回类型,后续括号内的变量为参数,{}大括号内的为函数体,即代码执行的主体。
dart中,返回值类型 和 参数类型 可以省略【但极其不推荐】
函数的简写(箭头形式)
函数支持箭头形式的简写,当函数体只有一行表达式时,可以通过=>
简写表示返回表达式的值。
int square(int x) => x * x;
int add(int a ,int b ) => a + b;
void add2(int a ,int b ) => a + b;
=>expr
是{ return expr; }
的简写。=>
后面的只能是表达式而非语句。
函数的调用
函数调用时通过函数名、(),加上传入的参数,即可执行一个函数。如下执行一个函数并将其返回值赋值给一个变量:
var result = add(1,2);
函数的参数
函数的参数分为命名参数、默认参数、位置参数、可选的位置参数等几种类型。
无参数函数
无参数函数没有任何参数。
下面的getInt
方法用于获取一个0~9的数字,没有任何参数。
import 'dart:math';
// 获取一个数字
int getInt(){
var random = new Random();
return random.nextInt(10);
}
位置参数
位置参数是最常见参数形式,每个参数以列表的形式位于()
内,调用时,也是根据位置,一个个的传入参数。
比如上面的add函数add(1,2);
。
定义一个求幂的函数:
int myPower(int num, int power) {
var result = 1;
for (int i = 0; i < power; i++) {
result *= num;
}
return result;
}
调用时,需要按照位置传入参数,位置不同,函数的执行结果就会不一样。
print(myPower(3, 2)); // 9
print(myPower(2, 3)); // 8
命名参数(可选)
使用{类型1 参数1, 类型2 参数2, …}
的形式来指定命名参数。命名参数默认是可选参数,也就是参数不是必须的,调用时可以不指定。如果希望命名参数必须传入,则需要指定required
标记。
命名参数的好处是,通过名称表示当前参数,使语义更加明确,知道指定的参数是哪个,而不像位置参数,需要通过函数定义或注释,才能知道哪个参数是什么含义;而且,命名参数是无顺序的,这样就不用按照固定顺序传入参数,尤其在参数非常多的时候,这非常方便,直接参数名语义化表示。
比如求幂的函数改为命名参数:
int myPower({
required int num,
required int power
}) {
var result = 1;
for (int i = 0; i < power; i++) {
result *= num;
}
return result;
}
命名参数的调用,通过参数名:值
的形式进行传参。明确传入对应的参数:
print(myPower(num: 3, power: 2));
print(myPower(power: 2, num: 3));
可以看到,无论传入的顺序,通过参数名指定值,明确的表示求数字3
的2
次幂。
由于命名参数是可选参数,因此参数可以不传入,那么,就要保证参数可为空,或者有一个默认值。
比如上面的myPower
函数,如果不标记required
,num
、power
又不能为空,可选不传入时就无法赋值null
,因此就会有如下错误:参数不能为null
值。
为其指定required
或默认值,下面默认求数字的平方:
int myPower({
required int num,
int power=2
}) {
var result = 1;
for (int i = 0; i < power; i++) {
result *= num;
}
return result;
}
调用时,可选指定参数:
print(myPower(num: 3)); // 9
可选的位置参数
使用 []
将一系列参数包裹起来作为可选的位置参数,既然是可选的,则可选的不用指定参数入参。
可选的位置参数必须按照参数位置传入,作为可选参数,其值必须是可为null
的,否则必须有一个默认值。
int myPower2(int num,[ int power=2]) {
var result = 1;
for (int i = 0; i < power; i++) {
result *= num;
}
return result;
}
调用方式,和普通的多参数函数一样:
print(myPower2(5)); // 25
print(myPower2(5,6)); // 15625
DateTime
类的构造函数就是可选位置参数最典型的应用,其中必须传入 year
参数。之后的参数为可选位置参数,是选填的,但必须按照顺序进行填写。
DateTime(int year,
[int month = 1,
int day = 1,
int hour = 0,
int minute = 0,
int second = 0,
int millisecond = 0,
int microsecond = 0])
DateTime(2022,10);
DateTime(2035,10,10);
默认参数
在可选的命名参数和可选的位置参数中,可以使用=
为参数指定默认值。表示在未指定此参数时,所使用的默认值。{类型 参数名 = 默认值}
默认值必须为编译时常量,没有指定默认值的情况下默认值为 null。
上面的示例中,已经演示了默认参数的情况:int myPower({ required int num, int power=2 })
,int myPower2(int num,[ int power=2])
main函数
每个 Dart 程序都必须有一个 main()
顶级函数作为程序的入口。
main()
函数返回值为 void
并且有一个 List<String>
类型的可选参数。
void main() {
print('Hello, World!');
}
List<String>
作为参数时,主要接收程序启动时传入的参数,比如命令行传入的选项。
void main(List<String> arguments) {
print(arguments);
}
返回值
Dart中所有函数都有返回值。
通过return
语句可以显式的返回一个对象。没有返回语句的函数最后一行默认为执行 return null;
。
foo() {}
print(foo() == null); // true