文章目录
上篇介绍了Dart如何定义变量,以及它的内置类型,这篇将介绍如何定义函数、各类运算符、条件语句
一、函数
Dart的函数和kotlin类似,也是一个对象,函数既可以作为参数传递,也可以作为返回参数
1.定义函数
Dart定义函数的规则为:[返回类型] ([参数类型] 参数名, ...){ return 返回值 }
,可以看出通过Dart的类型推断返回类型
和参数类型
可以省略,但官方还是推荐写全
// 定义一个求和函数
int sum(int a, int b) {
return a + b;
}
main() {
print(sum(10, 20));
}
1.1 => 单行表达式
如果你的函数只有一个简单的表达式,可以使用=>
代替{}
的内容
// 定义一个求和函数
int sum(int a, int b) => a + b;
main() {
print(sum(10, 20));
}
2.参数
Dart的参数定义很灵活,也有可选参数、参数默认值
2.1 {} 命名参数
除了上面定义函数时必传参数的方式外,Dart也支持可选参数,其中一种为命名参数
命名参数使用{参数1,参数2,...}
规则定义,并且需要放置在必传参数后面。调用时非require修饰的可空命名参数
或可选参数具有默认值
可以不传递值,也可以对命名参数使用参数名:
进行指定值。命名参数传递时,可以放在任意位置
// 定义一个可选参数的求和函数
int sum(int a, {int? b}) {
if (b != null) return a + b;
return a;
}
main() {
print(sum(10));
// 指定参数b为10
print(sum(10, b: 10));
// 命名参数传递时,可以放在随意的位置
print(sum(b: 20, 30));
}
运行结果:
如果你想对某个命名参数设置为必填,可以使用require
关键字修饰该参数。不过因为定义时已经是可选参数了,所以require
的使用场景并不多
// 定义一个可选参数的求和函数
int sum(int a, {required int? b}) {
if (b != null) return a + b;
return a;
}
此时不传参数b的值,会报错:
2.2 [] 位置参数
另一种可选参数是位置参数,功能上比命名参数少一点,不能以参数名指定值、不能使用require
修饰,不能随意摆放传递参数位置
// 带有前缀的打印
prefixPrint(String info, [String? prefix]) {
if (prefix != null) return print(prefix + info);
print(info);
}
main() {
prefixPrint("info", "hi ");
}
2.3 参数默认值
我们可以对可选参数设置默认值,直接在定义时使用=
赋值即可,默认值必须为常量,命名参数require
修饰和参数默认值不能同时使用
// 打印信息默认为hi
hiPrint({String info = "hi"}) => print(info);
main() {
hiPrint(info: "hello");
hiPrint();
}
运行结果:
// 带有前缀的打印
prefixPrint(String info, [String prefix = ""]) {
return print(prefix + info);
}
main() {
prefixPrint("info", "hi ");
prefixPrint("info");
}
运行结果:
3.函数传递
上边提到过Dart中函数也是一个对象,可以赋值给一个变量,可以作为参数传递
// 定义函数
void hi() => print("hi");
// action参数为一个函数,在打印前,调用一次该函数
void combinePrint(String info, void action()) {
action();
print(info);
}
main() {
// 函数赋值给变量
var printHi = hi;
// 调用函数变量
printHi();
combinePrint("打印前调用hi函数", hi);
}
运行结果:
4.匿名函数
函数也可以通过匿名方式创建,和定义函数的方式差不多
下面的程序有点无聊,我们定义一个具名函数callFunction
,它有三个参数,分别是int型的a
和b
,还有一个接收两个int值参数的函数参数function
,我们将callFunction
的a
,b
参数又传递给function
函数使用,获取值并打印。
调用callFunction
时,我们使用了匿名函数
// 调用函数参数的函数
void callFunction(int a, int b, int function(int a, int b)) {
// 传入的a,b,传递给function
var result = function(a, b);
// 打印结果
print(result);
}
main() {
// 传入一个匿名函数
callFunction(10, 20, (a, b) {
return a - b;
});
}
运行结果:
匿名函数如果只有单行表达式,也支持=>
方式定义:
main() {
// 传入一个匿名函数
callFunction(10, 20, (a, b) {
return a - b;
});
callFunction(10, 20, (a, b) => a + b);
}
二、运算符
Dart运算符和常规的类似,下面直接列出列表方便快速浏览
1.算术运算符
区别:/
是除,返回一个double
类型;~/
才是取整
运算符 | 描述 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
~/ | 取整 |
% | 取模 |
++ | 数+1,前置返回当前数+1,后置返回当前数 |
-- | 数-1,前置返回当前数-1,后置返回当前数 |
2.关系运算符
运算符 | 描述 |
---|---|
== | 相等 |
!= | 不等 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
3.类型判断运算符
运算符 | 描述 |
---|---|
as | 类型转换(也用作指定 库前缀)) |
is | 如果对象是指定类型则返回 true |
is! | 如果对象是指定类型则返回 false |
4.赋值运算符
4.1 ??= 可空变量赋值
由于Dart中可空变量的存在,除了直接使用=
给非空变量赋值外,还可以使用??=
为可空变量赋值,它将在变量为空时执行赋值操作,不为空时不进行赋值
main() {
int? i;
i ??= 1;
i ??= 2;
print(i);
}
为不是空的可空变量赋值时,会报出一个警告,运行结果:
4.2 其他赋值运算符
运算符 | 描述 |
---|---|
= | 赋值 |
*= | 乘后赋值 |
%= | 取模后赋值 |
>>= | 右移后赋值 |
>>>= | 无符号右移后赋值 |
^= | 幂后赋值 |
+= | 加后赋值 |
/= | 除后赋值 |
<<= | 左移后赋值 |
<<<= | 无符号左移后赋值 |
&= | 与后赋值 |
` | =` |
-= | 减后赋值 |
~/= | 取整后赋值 |
5.逻辑运算符
运算符 | 描述 |
---|---|
!*表达式* | 对表达式结果取反(即将 true 变为 false,false 变为 true) |
|| | 逻辑或 |
&& | 逻辑与 |
6. 按位和移位运算符
运算符 | 描述 |
---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
~*表达式* | 按位取反(即将 “0” 变为 “1”,“1” 变为 “0”) |
<< | 位左移 |
>> | 位右移 |
>>> | 无符号右移 |
7.条件运算符
Dart除了三目运算符,还有空运算符
7.1 条件 ? 表达式1 : 表达式2
条件为 true
,执行 表达式1
并返回执行结果,否则执行 表达式2
并返回执行结果。
7.2 表达式1 ?? 表达式2
如果表达式1
为非 null
则返回其值,否则执行表达式2
并返回其值。
8.级联运算符
级联运算符也是方便对变量进行配置,不过没有kotlin的函数式编程好用
8.1 …
..
:同一个对象上连续调用多个对象的变量或方法,使用时注意;
只有一个
class P {
var name;
var password;
}
main() {
var p = P()
..name = "zhangsan"
..password = "123";
print(p.name);
print(p.password);
}
运行结果:
8.2 ?..
如果对象可能为空,那么使用?..
可以在不为空时才进行操作
class P {
var name;
var password;
}
// 返回一个空
P? getP() {}
main() {
var p = getP()
?..name = "zhangsan"
..password = "hi";
print(p);
}
运行结果:
9.其他运算符
运算符 | 名字 | 描述 |
---|---|---|
() | 使用方法 | 代表调用一个方法 |
[] | 访问 List | 访问 List 中特定位置的元素 |
?[] | 判空访问 List | 左侧调用者不为空时,访问 List 中特定位置的元素 |
. | 访问成员 | 成员访问符 |
?. | 条件访问成员 | 与上述成员访问符类似,但是左边的操作对象不能为 null,例如 foo?.bar,如果 foo 为 null 则返回 null ,否则返回 bar |
! | 空断言操作符 | 将表达式的类型转换为其基础类型,如果转换失败会抛出运行时异常。例如 foo!.bar ,如果 foo 为 null,则抛出运行时异常 |
三、条件语句
Dart条件语句和Java几乎一样
if
和else
:else
可选for
循环:可迭代对象支持:for(i in iterator)
while
和do
-while
循环break
和continue
switch
和case
:case
依然需要和break
配合,使用==
来比较整数、字符串或编译时常量
1.assert 断言
断言使用assert(表达式)
,表达式为true
,程序继续执行,否则抛出AssertionError
异常。在Flutter中,调试模式断言会起作用,但生产环境代码中,断言会被忽略
四、异常
与 Java 不同的是,Dart 的所有异常都是非必检异常,方法不必声明会抛出哪些异常,并且你也不必捕获任何异常。
1.抛出异常
除了抛出一个具体的 Exception
和 Error
两种类型的异常:
throw FormatException('Expected at least 1 section');
Dart还可以随意抛出一个对象作为异常:
throw "hi";
2.捕获异常
2.1 catch
常规的try-catch-finally
方式:
main() {
var i;
try {
assert(i != null);
} catch (e) {
print(e);
} finally {
print("finally");
}
print("next..");
}
运行结果:
catch
还支持第二个参数,第二个参数为栈信息 StackTrace
对象:
main() {
var i;
try {
assert(i != null);
} catch (e, s) {
print("Exception:$e");
// 输出栈信息
print("Stack :$s");
} finally {
print("finally");
}
print("next..");
}
运行结果:
2.2 on
如果你不关心异常对象,那么可以使用on
指定是什么异常类型
main() {
try {
throw FormatException("too later");
} on FormatException {
print("太晚了");
}
}
运行结果:
当然也可以和catch
组合使用:
main() {
try {
throw FormatException("too later");
} on FormatException catch (e) {
print("太晚了");
print(e);
} on Exception {
print("Exception");
}
}
运行结果:
3.重新抛出
rethrow
可以将异常再次抛出
main() {
try {
throw FormatException("too later");
} catch (e) {
print(e);
rethrow;
}
}
运行结果: