学Flutter就和学iOS一样,先学基本语言语法的使用,再学习搭UI,iOS是OC和Swift,Flutter么就是Dart,语言学多了语法都差球不多,特别是这些新的语言,很多东西都是相似的,但是长时间不用容易忘记,与其每次去网上瞎jb找,不如自己总结一些,以后看自己写的东西就行了。文中个别结论是我自己总结出来的,不能保证准确性,看到的同学仅供参考。
本章提纲:
1.函数
2.函数的参数
3.匿名函数
4.运算符
函数
1.Dart也是面向对象语言,所以即使函数也是对象,所有也有类型,函数的类型就Function
,这个和Swift中一样的哇,函数都是一等公民,意味着你可以将函数作为变量定义或者作为其他函数的参数或者返回值。如果函数中只有一个表达式,那么可以使用箭头语法(arrow syntax)。
//定义一个函数
int sum(num num1, num num2) {
return num1 + num2;
}
//省略返回值的类型依然是可以的
sum(num num1, num num2) {
return num1 + num2;
}
//注意,这里面只能是一个表达式,不能是一个语句
sum(num1, num2) => num1 + num2;
函数的参数
1.函数的参数可以分成两类: 必须参数和可选参数,必须参数么就是函数基本的参数,可选参数可以分为命名可选参数和位置可选参数。
// 命名可选参数,age和height就是可选参数
printInfo1(String name, {int age, double height}) {
print('name=$name age=$age height=$height');
}
// 调用printInfo1函数
printInfo1('tong'); // name= tong age=null height=null
printInfo1('tong', age: 18); // name= tong age=18 height=null
printInfo1('tong', age: 18, height: 1.88); // name= tong age=18 height=1.88
printInfo1('tong', height: 1.88); // name= tong age=null height=1.88
2.命名可选参数, 可以指定某个参数是必传的,使用@required
标记,这点在第一次看的时候不是很理解,因为既然是可选参数了,为啥又可以要求必传,要求必传直接设为必传参数不就行了,这两者感觉有点矛盾,后来看官方很多类里面都这么用的,目前还没体会到这种用法的优势在哪。
补充:看到后面官方文档有个解释我觉得还算能说的过去,就是为啥不用必传参数是因为在Flutter里很多widget的属性很多,如果用必传参数调用的时候看不到方法名,不知道传的是哪个参数,而使用命名可选+@requierd
就可以实现既可以看到方法名,方便外部调用,也可以有必传参数的限制了,更多的是方便使用。
intInfo3(String name, {int age, double height, @required String address}) {
print('name=$name age=$age height=$height address=$address');
}
3.位置可选参数,调用的时候参数的顺序不能调换。
// 定义位置可选参数
printInfo2(String name, [int age, double height]) {
print('name=$name age=$age height=$height');
}
// 调用printInfo2函数
printInfo2('why'); // name=why age=null height=null
printInfo2('why', 18); // name=why age=18 height=null
printInfo2('why', 18, 1.88); // name=why age=18 height=1.88
4.可选参数默认值
// 参数的默认值
printInfo4(String name, {int age = 18, double height=1.88}) {
print('name=$name age=$age height=$height');
}
函数是一等公民
上面说过了,可以把函数当做其他类型的变量一样在各个场合使用。
main(List<String> args) {
// 1.将函数赋值给一个变量
var bar = foo;
print(bar);
// 2.将函数作为另一个函数的参数
test(foo);
// 3.将函数作为另一个函数的返回值
var func =getFunc();
func('tong');
}
// 1.定义一个函数
foo(String name) {
print('传入的name:$name');
}
// 2.将函数作为另外一个函数的参数
test(Function func) {
func('tong');
}
// 3.将函数作为另一个函数的返回值
Function getFunc() {
return foo;
}
匿名函数
没有名字的函数又称为匿名函数,也可以叫lambda或者closure,这玩意儿基本每种语言里都有,叫法不一样,OC叫block,原理都差不多。
main(List<String> args) {
// 1.定义数组
var movies = ['西游记', '东游记', '南游记', '北游记'];
// 2.使用forEach遍历: 有名字的函数
printElement(item) {
print(item);
}
movies.forEach(printElement);
// 3.使用forEach遍历: 匿名函数
movies.forEach((item) {
print(item);
});
movies.forEach((item) => print(item));
}
函数返回值
所有函数都返回一个值。如果没有指定返回值,则隐式返回null附加到函数体。
运算符
基本的+-*/和其他语言一样,主要记录一下Dart特有的几个运算符。
1.整除运算~/
var num = 7;
print(num ~/ 3); // 整除操作, 结果2;
2.??=
赋值操作
当变量为null
时,使用后面的内容进行赋值。当变量有值时,使用自己原来的值。
main(List<String> args) {
// var name2 = 'tong';
var name2 = null;
name2 ??= 'chao';
print(name2); // 当name2初始化为tong时,结果为tong,当初始化为null时,赋值了chao
}
3.条件运算符??
expr1 ?? expr2
,如果expr1
是null
,则返回expr2
的结果;如果expr1
不是null
,直接使用expr1
的结果。
var temp = 'why';
var temp = null;
var name = temp ?? 'kobe';
print(name);
4.级联语法:..
可以对一个对象进行连续的操作。除了调用函数,还可以访问同一对象上的字段属性。 这通常可以节省创建临时变量的步骤,同时编写出更流畅的代码。
main(List<String> args) {
final p1 = Person();
p1.name = 'tong';
p1.run();
p1.eat();
p1.swim();
//级联语法
final p2 = Person()
..name = "tong"
..run()
..eat()
..swim();
}
5.类型判定运算符
as
,is
,和 is!
运算符用于在运行时处理类型检查。is
运算符判断对象是否为某种类型,as
运算符将对象强制转换为特定类型。
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
如果emp
为null
或者不是Person
对象, 那么第一个is
的示例,后面将不回执行; 第二个as
的示例会抛出异常。
6.?.
取值操作
使?.
来代替.
,可以避免因为左边对象可能为null
,导致的异常:
// 如果 p 为 non-null,设置它变量 y 的值为 4。
p?.y = 4;
运算符重写
有的语言里叫运算符重载,都是为原来不支持这种操作的数据类型赋予这种运算的能力,方便使用。这玩意儿OC也没有,古老特点之三。
重载时需要用到operator
这个关键字,后面跟上要重载的运算符,下面就举个简单的+
和-
重载的例子,其他的用法还蛮多,==
的重载还要涉及到hash
和isEqual
吧,这个应该所有语言都差不多,具体的可以去网上专门搜一下,贴个
传送门,这具体用到的时候再细看吧。
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
}
流程控制
1.for循环
除了基本的for-i和for-in循环之外,Dart对于实现了Iterable 接口的对象提供了forEach() 方法,如果不需要使用当前计数值, 使用 forEach()
是非常棒的选择。
candidates.forEach((candidate) => candidate.interview());
2.switch-case
每个case
结尾需要加break
,空case
可以穿透,在非空case
中实现fall-through形式,可以使用continue
语句结合lable的方式实现:
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.
nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}