flutter學習-day3-dart基礎

本文學習和引用自《Flutter實戰(zhàn)·第二版》:作者:杜文

1. 變量聲明

  • var

類似于 JavaScript 中的var,它可以接收任何類型的變量,但最大的不同是 Dart 中 var 變量一旦賦值,類型便會確定,則不能再改變其類型:

var name = "李四"
/// 對
name = "張三"
/// 錯
name = 1000
  • Object

Object 是 Dart 所有對象的根基類,也就是說在 Dart 中所有類型都是Object的子類(包括Function和Null),所以任何類型的數據都可以賦值給Object聲明的對象,且后期可以改變賦值的類型。但是聲明的對象只能使用 Object 的屬性與方法, 否則編譯器會報錯。

Object t = 1000

t = "張三"

print(t.length) // 錯
  • dynamic

任何類型的數據都可以賦值給dynamic聲明的對象,且聲明的變量都可以賦值任意對象,且后期可以改變賦值的類型。而編譯器會提供所有可能的組合給聲明的對象,這個特點使得我們在使用它時需要格外注意,比如下面代碼在編譯時不會報錯,而在運行時會報錯:

dynamic t

t = "王五"

print(t.xxx) // 錯
  • final

如果您從未打算更改一個變量,那么可以使用 final。一個 final 變量只能被設置一次。它是一個運行時常量,final變量在運行時才知道其值,用于防止變量在程序運行期間被改變。

  • const

如果您從未打算更改一個變量,那么可以使用 const。與final的區(qū)別是,const 變量是一個編譯時常量,其值必須在聲明時就確定。(編譯時直接替換為常量值)用于創(chuàng)建編譯時常量,以便進行性能優(yōu)化。

  • 空安全

Dart 中一切都是對象,這意味著如果我們定義一個數字,在初始化它之前如果我們使用了它,假如沒有某種檢查機制,則不會報錯。如下:

test() {
  int i; 
  print(i*8); // 錯
}

在 Dart 引入空安全之后,如果一個變量沒有初始化,則不能使用它,否則編譯器會報錯:

int a = 10

聲明時候可以加上?,指定變量是可空:

String? name;

如果我們預期變量不能為空,但在定義時不能確定其初始值,則可以加上late關鍵字,表示會稍后初始化,但是在正式使用它之前必須得保證初始化過了,否則會報錯:

late int c;

c = 100

如果一個變量我們定義為可空類型,且判空了,但是預處理器仍然有可能識別不出,這時我們就要在變量后面加一個!符號,告訴預處理器它已經不是null了。

class Test() {
  int? d;
  log() {
    if (d! = null) {
      print(d! * 100)
    }
  }
}

如果函數變量可空時,調用的時候可以用語法糖:

fun?.call()
  • 特殊聲明模式
// 同時聲明
var (a, [b, c]) = ('str', [1, 2])

// 同時聲明
var (c, d) = ('left', 'right');

// 交換2個值
(c, d)  = (d, c)

// 解構
var (name, age) = userInfo(json)

// 省略符 
var (a, b, ...rest) = [1, 2, 3, 4, 5, 6] // 1 2 [3,4,5,6]

var (a, b, ...rest, c, d) = [1, 2, 3, 4, 5, 6] // 1 2 [3,4] 5 6

var (a, b, ..., c, d) = [1, 2, 3, 4, 5, 6] // 1 2 5 6

2. 操作符

  • 算數運算符
符號 意義 描述
+ -
- -
* -
/ -
~/ 返回整數結果
% 取余 獲取整數除法的余數
  • 等于運算符
符號 意義 描述
== 平等 -
!= 不相等 -
> 大于 -
< 小于 -
>= 大于或等于 -
<= 小于或等于 -
  • 邏輯運算符
符號 意義 描述
! 反轉 -
或者 -
&& 并且 -
  • 賦值運算符
符號 意義 描述
= 賦值 -
*= 乘法賦值 -
+= 加法賦值 -
-= 減法賦值 -
/= 除法賦值 -
%= 取模賦值 -
~/= 返回除法整數結果賦值 -
= 按位或賦值 -
&= 按位與賦值 -
^= 按位異或賦值 -
<<= 左移賦值 -
>>= 右移賦值(保留符號位) -
>>>= 右移賦值(無符號右移) -
  • 類型運算符
符號 意義 描述
as 類型轉換斷言 -
is 如果對象具有指定的類型,則為 True -
is! 如果對象沒有指定的類型,則為 True -
// 如果您不確定該對象的類型是否為Person,則在使用對象之前用is檢查
if (employee is Person) {
  employee.firstName = 'Bob';
}
  • 按位運算符
符號 意義 描述
& -
| -
^ 異或 -
<< 左移 -
>> 右移 -
>>> 無符號右移 -
  • 條件表達式
語法 意義 描述
condition ? expr1 : expr2 賦值 三元表達式
expr1 ?? expr2 賦值 如果 expr1 為非 null,則返回其值; 否則,計算并返回 expr2 的值
?.xxx 短路 條件成員訪問
! 斷言 將表達式強制轉換為其基礎不可為 null 的類型
  • 級聯表示法

級聯允許您在同一對象上,進行一系列操作。

// 級聯語法
var paint = Paint()
  ..color = Colors.black
  ..strokeCap = StrokeCap.round
  ..strokeWidth = 5.0;

// 等價于如下語法
var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;
// 級聯語法
querySelector('#confirm')
  ?..text = 'Confirm'
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

// 等價于如下語法
var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();

3. 數據類型

關鍵字 描述
int 不大于 64 位的整數值
double 64 位(雙精度)浮點數
String 字符串,多行字符串可以用'''xxx'''
bool 字符串
Set
Map 地圖
List 列表
Symbol 符號
Null null
record 記錄
typedef 類型別名

4. 控制流

  • switch
int size = 2;

// 條件判斷
switch (size) {
  case 1:
    print('一');
  case [2, 3]:
    print('二 and 三')
  case [4 || 5]:
    print('四 or 五')
  case >= 6 && <= 10
    print('六 to 十')
}

// 條件賦值
var bg = Color.green

var isPrimary = switch (bg) {
  Color.red || Color.yellow || Color.blue => true,
  _ => false
}
  • for
var message = StringBuffer('Dart is fun');

for (var i = 0; i < 5; i++) {
  message.write('!');
}
  • fon-in
Map<String, int> listMap = {
  'a': 23,
  'b': 100,
};

for (final MapEntry(key: key, value: value) in listMap.entries) {
  print('鍵:$key 值:$value');
}
  • while
while (!isDone()) {
  doSomething();
}
  • do-while
do {
  printLine();
} while (!atEndOfPage());
  • 跳過和停止
while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}
  • if
if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}
  • if-case
// 接受一個名為pair的參數。如果pair的類型是[int x, int y],則返回一個Point(x, y)對象
if (pair case [int x, int y]) return Point(x, y);

5. 錯誤處理和捕獲

異常捕獲和JavaScript差不多

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // 特定的異常
  buyMoreLlamas();
} on Exception catch (e) {
  // 任何其他的例外
  print('Unknown exception: $e');
} catch (e) {
  // 沒有指定類型,處理所有類型
  print('Something really unknown: $e');
} finally {
  cleanLlamaStalls();
}
  • 若要部分處理異常, 同時允許它傳播, 使用關鍵字:rethrow
void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // 運行時錯誤
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // 允許調用者看到異常
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}
  • 斷言

在開發(fā)過程中,使用斷言語句,如果布爾條件為false,則觸發(fā)。如果條件為true,則不觸發(fā)。在生產代碼中,斷言將被忽略。

// assert(條件, 可選消息)
var sizi = 101;
assert(size < 100, "Error:size 小于 100!");

6. 函數

Dart是一種真正的面向對象的語言,所以即使是函數也是對象,并且有一個類型Function。這意味著函數可以賦值給變量或作為參數傳遞給其他函數,這是函數式編程的典型特征。

  • 函數聲明
bool isNoble(int ) {
  return atomicNumber > 40;
}

bool isNoble (int atomicNumber) => atomicNumber > 40;
  • 函數作為參數傳遞
//定義函數execute,它的參數類型為函數
void execute(var callback) {
  // 執(zhí)行傳入的函數
  callback();
}

// 調用execute,將箭頭函數作為參數傳遞
execute(() => print("xxx"))
  • 可選的位置參數
String say(String a, String b, [String? c]) {
  var result = '$a and $b';
  if (c != null) {
    result = '$result and $c';
  }
  return result;
}
  • 可選的命名參數
//設置[a]和[b]標志
void enableFlags({bool a, bool b}) {
  // ... 
}

// 調用函數時,可以使用指定命名參數
enableFlags(bold: true, hidden: false)

7. mixin

Dart 是不支持多繼承的,但是它支持 mixin??梢远x幾個 mixin,然后通過 with 關鍵字將它們組合成不同的類(同名會被最后的覆蓋)。如下例子:

class Person {
  say() {
    print('say');
  }
}

mixin Eat {
  eat() {
    print('eat');
  }
}

mixin Walk {
  walk() {
    print('walk');
  }
}

mixin Code {
  code() {
    print('key');
  }
}

class Dog with Eat, Walk{}
class Man extends Person with Eat, Walk, Code{}

8. 異步

Dart類庫有非常多的返回Future或者Stream對象的函數,這些函數被稱為異步函數。

8-1. Future

Future與JavaScript中的Promise非常相似。

// 使用Future.delayed 創(chuàng)建了一個延時任務,2秒后返回結果字符串,然后在then中接收異步結果并打印
Future.delayed(Duration(seconds: 2),(){
  return "hi world!";
}).then((data){
  // 執(zhí)行成功
  print(data);
}).catchError((e){
   //執(zhí)行失敗會走到這里  
   print(e);
}).whenComplete((){
   //無論成功或失敗都會走到這里
});
  • 多個異步:Future.wait
Future.wait([
  // 2秒后返回結果  
  Future.delayed(Duration(seconds: 2), () {
    return "hello";
  }),
  // 4秒后返回結果  
  Future.delayed(Duration(seconds: 4), () {
    return " world";
  })
]).then((results){
  print(results[0]+results[1]);
}).catchError((e){
  print(e);
});
  • 解決回調地獄:async/await
task() async {
  try{
    String id = await login("alice","******");
    String userInfo = await getUserInfo(id);
    await saveUserInfo(userInfo);
    // 執(zhí)行接下來的操作
  } catch(e){
    // 錯誤處理
    print(e);
  }
}

8-2. Stream

Stream 也是用于接收異步事件數據,和 Future 不同的是,它可以接收多個異步操作的結果(成功或失敗)。 也就是說,在執(zhí)行異步任務時,可以通過多次觸發(fā)成功或失敗事件來傳遞結果數據或錯誤異常。 Stream 常用于會多次讀取數據的異步任務場景,如網絡內容下載、文件讀寫等。

Stream.fromFutures([
  // 1秒后返回結果
  Future.delayed(Duration(seconds: 1), () {
    return "hello 1";
  }),
  // 拋出一個異常
  Future.delayed(Duration(seconds: 2),(){
    throw AssertionError("Error");
  }),
  // 3秒后返回結果
  Future.delayed(Duration(seconds: 3), () {
    return "hello 3";
  })
]).listen((data){
  print(data);
}, onError: (e){
  print(e.message);
},onDone: (){});

// 上述代碼依次輸出
// hello 1
// Error
// hello 3

本次分享就到這兒啦,我是@鵬多多,如果您看了覺得有幫助,歡迎評論,關注,點贊,轉發(fā),我們下次見~

PS:在本頁按F12,在console中輸入document.querySelectorAll('._2VdqdF')[0].click(),有驚喜哦

往期文章

個人主頁

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容