学习笔记,旨在于快速入门和学习Dart,其中可能会有理解错误,请指出,一起学习。
系列文章
2.1、Dart语言基础:变量、运算符
2.2、Dart语言基础:函数与闭包
2.3、Dart语言基础:面向对象
2.4、Dart语言基础:异步
2.5、Dart语言基础:库与包
...
一、概述
Dart中函数是一等公民,因此,其可当做函数参数,可复制给变量;
函数声明(与C语言类似)
void sayHello(String name) {
print('$name say hello!');
}
// Tom say hello!
sayHello('Tom');
虽然可以省略参数类型和返回值类型,但是推荐最好写明白。
- 箭头函数
当函数只有一条语句, 可以使用 箭头函数=> expr
进行简写。
void sayHello(String name) => print('$name say hello!');
// Tom say hello!
sayHello('Tom');
- 返回值:如果没有显示返回,则默认返回null
All functions return a value. If no return value is specified, the statement return null;
二、函数参数
- 参数的类型分为两种:
位置参数(positional parameters)
和命名参数(named parameters)
。
1、命名参数
语法格式1:{param1, param2, …}
,如下
void introduce_1({String? name, int? age}) {
print("$name and $age");
}
// 1、null and null
introduce_1();
// 2、null and 30
introduce_1(age: 30);
// 3、tom and 30
introduce_1(name: 'tom', age: 30);
调用函数时,可选参数可以不传递,其默认为
null
;命名参数,调用函数时的入参顺序 与定义的参数位置无关。
参数必须为 可选类型(即用
?
标记);调用方式func(paramName: value)
;
void introduce_10({String name, int age}) {
print("$name and $age");
}
// 编译器报错:类型不匹配的错误
Error: The parameter 'name' can't have a value of 'null' because of its type 'String', but the implicit default value is 'null'.
Error: The parameter 'age' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
必选参数
- 标记为必须参数,关键字
required
;
函数调用时,required 参数
必须入参,否则编译报错。
void introduce_1_2({required String? name, int? age}) {
print("$name and $age");
}
// Error: Required named parameter 'name' must be provided.
introduce_1_2(age: 30);
// tom and null
introduce_1_2(name: 'tom');
默认参数
- 支持
默认参数
函数调用时,默认参数
可传递也可不传递。
void introduce_1_1({String? name='def', int? age}) {
print("$name and $age");
}
// 1、def and 30
introduce_1_1(age: 30);
// 2、tom and 30
introduce_1_1(name: 'tom', age: 30);
另一种语法格式:{param1: value1, param2: value2, ...}
,需要指定默认值
void introduce_2({name: 'err', age: 0}) {
print("$name and $age");
}
// 1、err and 0
introduce_2();
// 2、err and 30
introduce_2(age: 30);
// 3、tom and 30
introduce_2(name: 'tom', age: 30);
2、位置参数(positional parameters)
void say_1(String from, String msg) {
print('$from says $msg');
}
// 1、tom says hello world!
say_1('tom', 'hello world!');
// 2、Error: Too few positional arguments: 2 required, 1 given.
say1('tom');
- 调用函数时,
位置参数
必须传递全部参数,且顺序必须一致,类型也必须一致。
String say_1_1(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
// 1、Bob says Howdy
print(say_1_1('Bob', 'Howdy'));
// 2、Bob says Howdy with a smoke signal
print(say_1_1('Bob', 'Howdy', 'smoke signal'));
可选位置参数
- 支持声明 可选的
位置参数
;语法格式:[可选位置参数列表]
,如上。 - 调用时候,可选的位置参数可以不传递。
String say_1_2(String from, String msg, [String? device = 'iphone']) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
// 1、Bob says Howdy with a smoke signal
print(say_1_2('Bob', 'Howdy', 'smoke signal'));
// 2、Bob says Howdy with a iphone
print(say_1_2('Bob', 'Howdy'));
- 可选位置参数,支持默认参数。如上
3、默认参数值
- 位置参数 和 命名参数 都支持设置函数的默认值;语法格式:
param = value
,具体如上。 - 默认值只能是
编译时常量
, 如果没有提供默认值,则默认值为 null。
The default values must be compile-time constants. If no default value is provided, the default value is null.
4、一个函数可以同时定义 命名参数
和 位置参数
void sayHelloworld_1(String name, {int? age}) {
print("$name say hello,and age is $age!");
}
// 1、tom say hello,and age is null!
sayHelloworld_1('tom');
// 2、tom say hello,and age is 30!
sayHelloworld_1('tom', age: 30);
- 调用函数时,可选的命名参数,可以不传递。
三、匿名函数,Anonymous functions
- 其他语言,被称为lambda 或 闭包closure。
- 语法格式:
([[Type] param1[, …]]) {
codeBlock;
};
const list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
// 输出如下:
0: apples
1: bananas
2: oranges
- 上面以数组的
forEach
遍历方法为例:
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
- 单一语句,可以是会用箭头函数
四、作用域(词法)
1、词法作用域 Lexical scope
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
Dart 是一门词法作用域的编程语言,就意味着变量的作用域是固定的。
Dart is a lexically scoped language, which means that the scope of variables is determined statically, simply by the layout of the code.
可简单的从代码层次结构上看出来,即变量的作用范围,仅局限在其
花括号{}
内。
You can “follow the curly braces outwards” to see if a variable is in scope.
2、词法闭包 Lexical closures
闭包本质是一个函数对象,因此其可以 捕获变量 到 闭包的作用域内;即使函数在其原来作用域内使用。
A closure is a function object that has access to variables in its lexical scope, even when the function is used outside of its original scope.
函数可以 捕获 在其作用域范围内定义的变量。
Functions can close over variables defined in surrounding scopes.
makeAdder()
捕获了 变量addBy
到闭包的作用域内。
In the following example, makeAdder() captures the variable addBy. Wherever the returned function goes, it remembers addBy.
Function makeAdder(int addBy, String name) {
return (int i) => '${addBy + i} $name';
}
var add2 = makeAdder(2, 'aaa');
var add4 = makeAdder(4, 'bbb');
print(add2(3)); // 5 aaa
print(add4(3)); // 7 bbb