希望在閱讀本文之前,你已經閱讀了:
Flutter之旅:Dart的基礎語法
Flutter之旅:從原始碼賞析Dart物件導向
1、其他常用符號與關鍵字
1.1:級聯操作符:..
那Paint物件的設定來看:
---->[情景1:曾經的寫法]----
var paint = Paint();
paint.strokeCap = StrokeCap.round;
paint.style = PaintingStyle.stroke; //畫線條
paint.color = Color(0xffBBC3C5); //畫筆顏色
paint.isAntiAlias = true; //抗鋸齒
paint.filterQuality = FilterQuality.high; //抗鋸齒
---->[情景2:級聯的寫法]----
paint
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke //畫線條
..color = Color(0xffBBC3C5) //畫筆顏色
..isAntiAlias = true //抗鋸齒
..filterQuality = FilterQuality.high;
複製程式碼
很簡潔,很高大上有木有,
1.2: 條件呼叫符:?.
---->[情景1:普通呼叫]----
void main() {
var a = -5;
print(a.abs());//5
}
---->[情景2:普通呼叫前置空,會崩掉]----
var a = 5;
a=null;
print(a.abs());//NoSuchMethodError: The method 'abs' was called on null.
---->[情景3:?.呼叫不會崩掉,只返回null]----
var a = 5;
a = null;
print(a?.abs()); //null
複製程式碼
1.3:型別判斷關鍵字、is
、 is!
和as
var b=10;
print(b is String);//false
print(b is num);//true
print(b is! double);//true
String c="12315";
print((c as Comparable<String>).compareTo("a"));//-1 強制型別轉換
print((c as num).abs());//型別轉換異常
// type 'String' is not a subtype of type 'num' in type cast
複製程式碼
2.庫的使用和可見性
2.1:庫的基本使用
import 'dart:math';//匯入math內建庫
import 'package:flutter/material.dart';//根據檔案系統路徑到包
複製程式碼
2.2:類庫中的命名衝突: as
關鍵字的使用
當sin函式處於連個包中,並且兩個包都被匯入,該怎麼辦
---->[utils/color_utils.dart]----
sin(double d){
}
---->[main.dart:5]----
import 'package:toly/utils/color_utils.dart';
import 'dart:math';
void main() {
sin(5);
}
---->[解決方案]----
import 'package:toly/utils/color_utils.dart' as myMath;
import 'dart:math';
void main() {
myMath.sin(5);
}
複製程式碼
2.3:控制顯隱部分匯入
被隱藏的物件無法被外界訪問
import 'package:toly/utils/color_utils.dart' show sin;//只顯示sin函式
import 'package:toly/utils/color_utils.dart' hide sin;//只隱藏sin函式
複製程式碼
2.4:許可權訪問控制
需要注意的是,Dart中沒有private,public,protected修飾符。 如何做到訪問許可權控制,是個問題,預設是可以被訪問的。
---->[painter/person.dart]----
class Person{
String name;
int age;
Person(this.name,this.age);
say(){
print("my name is $name and i am $age years old.");
}
}
---->[main.dart]----
import 'package:toly/painter/person.dart';
void main() {
var toly = Person("toly", 25);
print(toly.age);//25
toly.say();//my name is toly and i am 25 years old.
}
複製程式碼
Dart中規定,名稱前加下劃線可以限制外部的訪問,如下_age。
方法名,檔名也是如此,不想對外暴露,前面加下劃線即可
---->[painter/person.dart]----
class Person{
String name;
int _age;
Person(this.name,this._age);
say(){
print("my name is $name and i am $_age years old.");
}
}
---->[main.dart]----
void main() {
var toly = Person("toly", 25);
toly.say();//my name is toly and i am 25 years old.
print(toly._age);//報錯
}
複製程式碼
2.5:library
和export
關鍵字的使用
這裡拿animation來舉例子,使用時導包:
import 'package:flutter/animation.dart';
在原始碼中animation.dart只做了一個歸納暴露的動作。
library animation;
export 'src/animation/animation.dart';
export 'src/animation/animation_controller.dart';
export 'src/animation/animations.dart';
export 'src/animation/curves.dart';
export 'src/animation/listener_helpers.dart';
export 'src/animation/tween.dart';
export 'src/animation/tween_sequence.dart';
複製程式碼
3.泛型
Dart中的泛型和Java中非常相似,可以讓型別變得安全,程式碼更加優雅。
3.1:泛型的使用
拿List類來說,在類定義時類名List後加了,在使用時List就可以加一個型別。這樣的好處在於當你試圖新增其他型別的資料到該List物件中時,會報錯。這樣就是的型別變得安全。
---->[sky_engine/lib/core/list.dart:54]----
abstract class List<E> implements EfficientLengthIterable<E> {
---->[main.dart]----
void main() {
var languages=List<String>();//定義一個泛型為String的列表
var odd=List<int>();//定義一個泛型為int的列表
}
複製程式碼
3.2:List,Map,Set特殊的初始化
這並不算泛型特點,只是List,Map,Set快速初始化的寫法。
只不過看起來有些奇怪,這裡說一下,以後會常見這些寫法。
var languageList = <String>['Java', 'Dart', 'Kotlin'];
var markMap = <String,int>{'Java':100, 'Dart':80, 'Kotlin':60};
var languageSet = <String>{'Java', 'Dart','Kotlin'};
複製程式碼
3.3:泛型的限定
和Java語法一致,使用 來限定泛型的型別區域
如下面DiagnosticableNode中的泛型限定
class DiagnosticableNode<T extends Diagnosticable> extends DiagnosticsNode
複製程式碼
3.4:泛型方法
在Dart中,方法也是可以支援泛型的,比如下面的方法:
當呼叫var e = foo<int>("hello");
則會報錯,改為foo<String>
即可。
T add<T>(T t) {
return t;
}
複製程式碼
4.非同步操作簡介
關於非同步,是一個挺大的話題,這裡簡單提一下,之後有詳細介紹。
4.1:非同步在Dart中的必要性
Dart是一個單執行緒的程式語言,耗時操作會造成執行緒阻塞。
就相當於我在燒開水,水燒開之前都無法進行其他動作,這顯然是不合理的。
我完全可以在燒水的時候去掃地,等水開了再去處理,需要一個Future物件用於後續處理
class Water{
double temperature;
Water(this.temperature);
Future<Water> changeTemperature(double t) {
for(var i=0.0;i<=t;i+=0.01){//模擬燒水過程(耗時操作)
temperature=i;
}
return Future<Water> (()=>this);
}
}
複製程式碼
4.2:async
和await
關鍵字的使用
async表示非同步,await表示等待。注意在非同步操作中返回的是Future物件
這個物件用於,後續的處理,比如水燒開後去沖水什麼的。
Future<Water> heat(Water water) async{//非同步燒水
return await water.changeTemperature(100);//返回燒開的水的Future
}
main(){
print("開啟燒水開關");
heat(Water(0)).then((result){
print('水已經燒開,現在溫度:${result.temperature},開始沖水');
});
print("掃地");
}
複製程式碼
可以卡看出,開啟燒水開關後,接著是掃地,水燒開後再衝水,這就是非同步操作。
更多的用法將在後面檔案資源的讀取時做詳細闡述。
5.異常處理
5.1:異常不處理的情況
結果由於
FormatException
異常,程式直接崩潰
這並不是我們想要的,直接崩潰會造成極差的使用者體驗。
void main() {
print(str2Num("a"));//FormatException: a
}
num str2Num(String str){
return num.parse(str);
}
複製程式碼
5.2:異常捕捉
這個和Java也是類似的,使用try...catch...finally程式碼塊
這樣異常會通過日誌列印並且程式不會崩潰退出。 其中finally程式碼塊中的語句不管異常與否,都會被執行
num str2Num(String str){
var result= 0;
try {
result= num.parse(str);
} catch (e) {
print('發生異常:$e');
} finally {
print('最終會被執行的程式碼塊');
}
return result;
}
複製程式碼
5.3:指定異常或多個異常捕捉
使用on關鍵字,可以指定捕捉某一類異常。
num str2Num(String str){
var result= 0;
try {
result= num.parse(str);
} on FormatException catch (e) {
print('發生Format異常:$e');
} on IOException catch(e){
print('發生IO異常:$e');
} finally {
print('最終會被執行的程式碼塊');
}
return result;
}
複製程式碼
6.Dart中的多繼承
知道Dart支援多繼承,我是挺驚訝的,多繼承的問題在於父類構造可能被迴圈呼叫
6.mixin的使用
6.1:子類和父類建構函式呼叫順序
通過下面的程式碼可以看出,是先呼叫父類的構造方法
class Living {
Living(){
print("Runner");
}
}
class Person extends Living{
Person(){
print("Person");
}
}
main(){
Person toly = Person();
}
---->[列印結果]----
Runner
Person
複製程式碼
6.2:mixin是什麼?
首先mixin是一個定義類的關鍵字。直譯出來是混入,混合的意思
Dart為了支援多重繼承,引入了mixin關鍵字,它最大的特殊處在於:
mixin定義的類不能有構造方法
,這樣可以避免繼承多個類而產生的父類構造方法衝突
class Living {
Living(){
print("Runner");
}
}
class Runner {
run(){
print("run");
}
}
class Walker{
walk(){
print("run");
}
}
class Person extends Living with Walker,Runner{
Person(){
print("Person");
}
}
main(){
Person toly = Person();
toly.run();
toly.walk();
}
複製程式碼
使用方法很簡單,在
with
關鍵字後面將類名,這是該類就是mixin類
mixin就相當於將其他類的能力混入到當前類,還是挺厲害的。
唯一的限制就是mixin類無法擁有建構函式,如果有構造方法會怎樣? 報錯唄。
6.3:關於mixin關鍵字
使用class關鍵字定義的類是可以當做mixin類使用的,比如上面的。
另外使用mixin關鍵字也可以來定義mixin類,如:
mixin Walker{
walk(){
print("run");
}
}
複製程式碼
唯一的區別在於,你是否確定它是一個mixin類。
當你在mixin宣告的類中定義構造方法,會直接報錯。
6.4:關於混入的方法重名
取後混入的
class Runner {
go(){
print("Runner-go");
}
}
mixin Walker{
go(){
print("Walker-go");
}
}
class Person with Runner,Walker{
Person(){
print("Person");
}
}
main(){
Person toly = Person();
toly.go();//Walker-go
}
複製程式碼
本文到此接近尾聲了,如果想快速嚐鮮Flutter,《Flutter七日》會是你的必備佳品;如果想細細探究它,那就跟隨我的腳步,完成一次Flutter之旅。
另外本人有一個Flutter微信交流群,歡迎小夥伴加入,共同探討Flutter的問題,本人微訊號:zdl1994328
,期待與你的交流與切磋。