Dart

09.Dart基础-函数(一)

内容纲要

Dart 是真正面向对象的语言,因此在 Dart 中即便是函数也是对象类型(类型为 Function)。因此在 Dart 中函数可以被赋值给变量,或者作为其它函数的参数

1. 定义函数

定义函数的完整语法格式为:

返回值类型 函数名(参数) {
  函数体逻辑代码
  return 返回值
}

下面的代码定义了一个无返回值show 函数,接收一个 String 类型的 name 参数,示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数
  show('liulongbin');
}

// 1. 声明无返回值的 show 函数
void show(String name) {
  print('大家好,我是 $name');
}

如果要定义有返回值的函数,则需要把 void 替换为返回值的类型,并在函数体的最后,使用 return 具体的返回值 来返回函数调用的结果。示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数,并得到返回值 res
  var res = show('liulongbin');
  // 3. 输出: 大家好,我是 LIULONGBIN
  print(res);
}

// 1. 声明有返回值的 show 函数
String show(String name) {
  return '大家好,我是 ${name.toUpperCase()}';
}

2. 函数参数

函数的参数分为两种类型:必要参数可选参数

  1. 必要参数:调用函数时必须要传递的、不可省略的参数
  2. 可选参数:调用函数时非必要的、可传可不传的参数。其中可选参数又分为两种:位置参数命名参数

2.1 必要参数

在 Dart 中,必要参数必须放在参数列表的最前面,如果存在多个必要参数,则多个必要参数必须放在可选参数之前。声明必要参数的语法格式为:

返回值 函数名(参数类型 必要参数1, 参数类型 必要参数2) {
  函数体
}

注意:多个必要参数之间用英文的 , 分隔

在调用函数时,如果存在多个必要参数,则传参的顺序必须和参数定义的顺序保持一致,示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数,必须按照参数列表的顺序依次传参
  // 输出:大家好,我是 escook,今年 23 岁了,体重 112.6 斤。
  show('escook', 23, 112.6);
}

// 1. 定义无返回值的 show 函数,并接收三个参数,分别是:
// 参数1:name 字符串类型
// 参数2:age 整数类型
// 参数3:weight 小数类型
void show(String name, int age, double weight) {
  print('大家好,我是 $name,今年 $age 岁了,体重 $weight 斤。');
}

2.2 位置参数

在 Dart 中,位置参数是可选的参数。定义位置参数的语法是:使用 [ ] 把位置参数包裹起来。因此,区分必要参数位置参数的好办法就是看它是否被 [ ] 包裹。语法格式如下:

返回值 函数名(参数类型 必要参数1, 参数类型 必要参数2, [参数类型? 位置参数1, 参数类型? 位置参数2]) {
  函数体
}

注意:[ ] 内部可以包含多个位置参数;而且每个位置参数的数据类型之后,需要添加 ? 表示可为 null 的类型。

2.2.1 定义单个位置参数

位置参数必须放在必要参数之后,单个位置参数表示 [ ] 中只包含一个位置参数。示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数,没有给位置参数 weight 传参
  // 输出:大家好,我是 escook,今年 23 岁了,体重 null 斤。
  show('escook', 23);

  // 3. 调用 show 函数,并给位置参数 weight 传参
  // 输出:大家好,我是 liulongbin,今年 18 岁了,体重 112.5 斤。
  show('liulongbin', 18, 112.5);
}

// 1. 定义函数 show
// name 和 age 是必要参数,调用函数 show 时必须要传值,否则报错
// weight 是可选参数,属于可选参数中的 "位置参数",因为它是用 [] 定义的
// double? 后面的 ? 表示可为 null 的 double 类型,当用户没有为 weight 传参时,默认值即 null
void show(String name, int age, [double? weight]) {
  print('大家好,我是 $name,今年 $age 岁了,体重 $weight 斤。');
}

2.2.2 定义多个位置参数

无论定义多少个位置参数,都必须把位置参数放到必要参数之后,因为“位置参数”代表的含义是“可选参数”。只需要把多个位置参数都放到 [ ] 中定义即可。示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数,只传递了必要参数 name 的值
  // 输出:大家好,我是 escook,今年 null 岁了,体重 null 斤。
  show('escook');

  // 3. 调用 show 函数,并只给必要参数 name 和第1个位置参数 age 赋值
  // 输出:大家好,我是 liulongbin,今年 18 岁了,体重 null 斤。
  show('liulongbin', 18);

  // 4. 调用 show 函数,传递了所有参数的值
  // 输出:大家好,我是 liulongbin,今年 18 岁了,体重 112.5 斤。
  show('liulongbin', 18, 112.5);

  // 5. 注意,不能在忽略前面位置参数的情况下,只为后面的位置参数传值,
  // 如果确实要这么做,请务必给前面所有的位置参数"赋具体的值或 null"。
  // 输出:大家好,我是 liulongbin,今年 null 岁了,体重 112.5 斤。
  show('liulongbin', null, 112.5);
}

// 1. 定义 show 函数,其中:
// 参数1:name 是必要参数
// 参数2:age 和 weight 是位置参数
void show(String name, [int? age, double? weight]) {
  print('大家好,我是 $name,今年 $age 岁了,体重 $weight 斤。');
}

位置参数”的缺点是无法忽略前面的位置参数,只为后面的位置参数赋值。传参的顺序必须和定义参数的顺序相同,这就是“位置参数”名称的由来。

2.3 命名参数

在 Dart 中,“命名参数”和“位置参数”一样,都是可选参数。定义命名参数的语法是: 使用 { } 把命名参数包裹起来。语法格式如下:

返回值 函数名(参数类型 必要参数1, 参数类型 必要参数2, {参数类型? 命名参数1, 参数类型? 命名参数2}) {
  函数体
}

注意:

  1. { } 内部可以包含多个“命名参数”;而且每个“命名参数”的数据类型之后,需要添加 ? 表示可为 null 的类型。
  2. 在函数的形参列表中,不能同时使用“位置参数”和“命名参数”,两者是互斥的。

2.3.1 定义单个命名参数

命名参数作为可选参数,必须放到必要参数之后,并使用 { } 包裹起来,示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数,只传递了必要参数
  // 输出:大家好,我是 escook,今年 18 岁了,体重 null 斤。
  show('escook', 18);

  // 3. 调用 show 函数,在传递所有必要参数的同时,使用 "命名参数名" 的方式为命名参数传值
  // 输出:大家好,我是 escook,今年 18 岁了,体重 112.5 斤。
  show('escook', 18, weight: 112.5);
}

// 1. 定义 show 函数,其中:
// 参数1:name 和 age 是必要参数
// 参数2:weight 是可为 null 的命名参数
void show(String name, int age, {double? weight}) {
  print('大家好,我是 $name,今年 $age 岁了,体重 $weight 斤。');
}

2.3.2 定义多个命名参数

多个命名参数必须放到参数列表的最后,且用 { } 包裹起来。示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数,只传递了必要参数
  // 输出:大家好,我是 escook,今年 null 岁了,体重 null 斤。
  show('escook');

  // 3. 调用 show 函数,除了传递必要参数之外,还传递了命名参数 age
  // 输出:大家好,我是 escook,今年 18 岁了,体重 null 斤。
  show('escook', age: 18);
  // 4. 调用 show 函数,除了传递必要参数之外,还传递了命名参数 weight
  // 输出:大家好,我是 escook,今年 null 岁了,体重 112.5 斤。
  show('escook', weight: 112.5);

  // 5. 调用 show 函数,除了传递必要参数之外,还分别传递了命名参数 age 和 weight
  // 输出内容相同,都是:大家好,我是 escook,今年 18 岁了,体重 112.5 斤。
  show('escook', weight: 112.5, age: 18);
  show('escook', age: 18, weight: 112.5);
}

// 1. 定义 show 函数,其中:
// 参数1:name 是必要参数
// 参数2:age 和 weight 是可为 null 的命名参数
void show(String name, {int? age, double? weight}) {
  print('大家好,我是 $name,今年 $age 岁了,体重 $weight 斤。');
}

相比于“位置参数”来说,“命名参数”的好处是:不受参数位置的限制,可以自由地为可选参数赋值。

2.3.3 用 required 修饰命名参数

默认情况下“命名参数”是可选参数。但是如果命名参数被 required 修饰了,那么被修饰的命名参数就变成了必选的命名参数。调用者必须为该命名参数提供一个参数值,否则会导致编译错误。示例代码如下:

void main(List<String> args) {
  // 2. 调用 show 函数,
  // 必须传递 name 的值,因为它是必选参数;
  // 必须传递 weight 的值,因为它是被 required 修饰的"必选的"命名参数;
  // 输出:大家好,我是 escook,今年 null 岁了,体重 112.5 斤。
  show('escook', weight: 112.5);
}

// 1. 定义 show 函数,其中:
// 参数1:name 是必要参数
// 参数2:age 是"可选的"命名参数
// 参数3:weight 是"必选的"命名参数,因此参数类型 double 后面的 ? 就可以去掉了
void show(String name, {int? age, required double weight}) {
  print('大家好,我是 $name,今年 $age 岁了,体重 $weight 斤。');
}

2.4 参数默认值

可以用 = 为函数的命名参数位置参数定义默认值,默认值必须为编译时常量,没有指定默认值的情况下默认值为 null。示例代码如下:

void main(List<String> args) {
  // 输出:大家好,我是 liulongbin,今年 18 岁了,体重 120.0 斤。
  show('liulongbin');

  // 输出:Hi, my name is escook, I'm 20 years old, my weight is 112.5.
  sayHi('escook');
}

// 1. 给命名参数提供参数默认值
void show(String name, {int age = 18, double weight = 120}) {
  print('大家好,我是 $name,今年 $age 岁了,体重 $weight 斤。');
}

// 2. 给位置参数提供参数默认值
void sayHi(String name, [int age = 20, double weight = 112.5]) {
  print('Hi, my name is $name, I\'m $age years old, my weight is $weight.');
}

注意:在实际开发中,“命名参数”和“参数默认值”是最佳开发实践,“位置参数”和“可为 null 的可选参数”应用场景较少。

3. 函数简写

如果函数体内只包含一个表达式,可以使用简写语法 =>,例如:

String show(String name) {
  return '大家好,我是 $name';
}

可以使用箭头函数 => 简写为:

String show2(String name) => '大家好,我是 $name';

其中,语法 => 表达式{ return 表达式; } 的简写, => 语法叫做箭头函数

一个不再讲课の前端程序员。

一条评论

留言

您的电子邮箱地址不会被公开。 必填项已用*标注