Flutter 学习 - Dart 中的 Function
最近开始学习 Flutter ,然后学道了 Dart 的函数,发现挺有意思的。
- Dart里面所有的东西都是对象,包括 int ,函数 这些对象的父类是Object.
- 如果一个函数也是对象,那么类型是啥呢? 答案是 Function ,这是 Dart 中的一种类型。这也就意味这函数可以被定义成一个变量,甚至可以可以被定义为一个参数传递给另外一个函数。
Function 格式 : 返回类型 函数名(参数列表){函数体}
返回类型
可以省略,因为返回值类型可以通过 return 的值类型推断出来的,如果没有 return ,那么返回类型自然就是 void 了,但是不建议这么做。
函数名
这个没啥好说的,符合命名规则就好,尽量名称能概括函数体的内容
Dart 认为重载会导致混乱,因此从设计之初就不支持重载,而是提供了可选命名参数和可选参数。
参数
分以下几种
- 正常的参数
- 可选命名参数
- 可选位置参数
- 默认值参数
正常的参数
这个和 java 一样,没啥好说的
可选命名参数
可以在函数传递参数时,指定参数名,这个在 Flutter 中经常看到。 定义的时候使用{}将形参包含起来,如下:
void sayHello({String name, String msg}) => print("$name: $msg");
注意:如果函数体只有一行表达式,我们还可以像 JavaScript 语言那样用箭头函数来简化这个函数。但是 在 => 和 ;之间只能是表达式,而不能是一条语句。
{}中的参数可传可不传,使用就如下了
void main() {
sayHello(name: "david", msg: "你好啊"); // david: 你好啊
sayHello(msg: "你好啊", name: "david",); // david: 你好啊
sayHello(msg: "hello"); //null: hello
sayHello(name: "david"); //david: null
sayHello();
}
可选的位置参数
语法格式 使用[] 进行包裹,如下
String say(String from, String msg , [String device, String time]) {
var result = "$from says $msg";
if (device != null) {
result = "$result with a $device";
}
if (time != null) {
result = "$result at $time";
}
return result;
}
void main(){
print(say("david", "hello", "mobile", "2019.2.29.20:08:08"));
// david says hello with a mobile at 2019.2.29.20:08:08
print(say("david", "hello", "2019.2.29.20:08:08", "mobile"));
// david says hello with a 2019.2.29.20:08:08 at mobile
print(say("david", "hello"));
// david says hello
}
- 同样作为可选参数,故在调用时可以不传
- 是通过位置来确定实参和形参的对应关系的
默认值参数
这个很简单,就是给 可选的命名参数或者 可选的位置参数指定默认值,因为他们都是可选的,
String say(String from, String msg , [String device = "mobile", String time = "2019.2.23.18:30:00"]) {
var result = "$from says $msg";
if (device != null) {
result = "$result with a $device";
}
if (time != null) {
result = "$result at $time";
}
return result;
}
给 device 和 time 都设置了默认值,如果不填写,就使用默认值了
然后我们需要再介绍几个新鲜词语 @required , 匿名函数,typedef
@required
可选参数列表中某个参数添加该注解,表示该参数为必须设置,有点像是必填项
匿名函数
语法 ([type] param){} 参数 类型可选,例如
void main(){
var list = [1, 2 , 3];
list.forEach((item) {
print(item);
});
}
typedef
给某种特定的函数类型起一个名字,可以认为是一个类型的别名, 可以类比 class 和对象这样理解:自己定义了一种数据类型,不过这种数据类型是一个函数类型,一个一个的具体实现的函数就相当于按照这种类型实例化的对象
//声明参数为 int ,无返回值的 callback 函数 MenuCallBack
typedef MenuCallBack = void Function(int position);
//声明一个参数为 context 和 int ,返回值是 Widget 的 callback 函数 IndexedWidgetBuilder
typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index);
//声明一个 参数为 BuildContext ,返回值 Widget 的 callback 函数 WidgetBuilder
typedef WidgetBuilder = Widget Function(BuildContext context);
例子说明
FlatButton(
onPressed: () {
Navigator.push(
context ,
MaterialPageRoute(
builder: (context) {
return NewRoute();
},
),
);
},
child: Text("点击跳转"),
)
相信这样的代码应该会经常看到,现在我们就来解剖一下这段代码的意思,还原一下他们的真实面貌
省略 new 关键字
因为我们知道在 Dart 创建对象的时候,可以省略到 new 关键字,上面代码已经省略了,现在我们把他们添加上去,
new FlatButton(
onPressed: () {
Navigator.push(
context ,
new MaterialPageRoute(
builder: (context) {
return new NewRoute();
},
),
);
},
child: new Text("点击跳转"),
)
FlatButton 和 MaterialPageRoute 以及 NewRoute , Text 前面都添加了,这是要创建三个对象,这三个也都是Widget
onPressed
我们继续看看第二行,也就是 onPressed 这一行 在看第二行之前,我们先看看 FlatButton 的构造函数
const FlatButton({
Key key ,
@required VoidCallback onPressed,
... 省略
@required Widget child,
})...
typedef VoidCallback = void Function();
我们可以得知
- 因为有{} 包裹 onPressed 和 child ,所以是可选命名参数
- 因为签名有 @required注解,所以 onPressed 和 child 又是必填参数,
- 因为 typedef VoidCallback = void Function(); 可知 onPressed 的类型是 一个返回值是 void ,无参数的 callback 函数 VoidCallback ,
所以综上所述, onPressed 是一个必填的参数,类型是一个返回值是 void ,无参数的函数, child 是一个类型是 Widget 的必填参数,这个后面说到,现在继续说onPressed onPressed: 后面是一个匿名函数,格式就是 (){},参数无
在点击的 FlatButton 的时候,会执行 这个匿名函数的函数体,也即时执Navigator.push()函数
Navigator.push()
push() 有两个参数,一个是 context ,一个是 Route context 上面有, Route 就需要重新创建了一个,即 new MaterialPageRoute() ,
创建 MaterialPageRoute 对象
先看 MaterialPageRoute 的构造函数
MaterialPageRoute({
@required this.builder,
RouteSettings settings ,
this.maintainState = true,
bool fullscreenDialog = false,
}):...省略
看到了{},可选参数,看到了 @required 注解,所以 builder 就是必填可选参数, 然后我们看看 builder 的定义吧
final WidgetBuilder builder;
typedef WidgetBuilder = Widget Function(BuildContext context);
类型是 WidgetBuilder ,其实就是返回类型是 Widget ,参数是 BuildContext 的 callBack 函数 ,既然他们要的是这样一个 callback 函数,那么就创建一个这样的函数
匿名函数
创建一个参数类型是 BuildContext , 返回值是 Widget 的 匿名函数,那么应该是 (BuildContext context) {return new Widget的();}
- 匿名函数中 参数类型可省略。
- 创建对象的时候, new 关键字 可以省略,
- NewRoute 是 继承 StatelessWidget ,属于一个 Widget 。
根据上面这三点,这个匿名函数就变成了 (context) {return NewRoute();} 这个鸟样。
然后还剩下一个 child 参数
child参数
创建了一个 Text() 对象,看看 Text 的构造函数
const Text(
this.data, {
Key key ,
...
}) ...
final String data;
看到了没, data 在{} 之外,也就是正常的参数,类型是 String 的,那么就需要给他传递值,即”点击跳转”,后面都是可选命名参数,所以可以不写。
搬运地址:
极客时间《Flutter核心技术与实战》
既已览卷至此,何不品评一二: