(四)Flutter學習之Dart操做符、控制流和異常處理

操做符

Dart 操做符和主流語言的操做符相似, 只要有一門經常使用語言, 對 Dart 掌握也是很快的bash

Dart 和之前介紹的 Kotlin 相似, 也提供操做符重載功能框架

算術操做符

Dart 支持下面經常使用的數學操做符:less

操做符 意義
+ 加號
- 減號
-expr 一元操做符,負號
* 乘號
/ 除號
~/ 除號,返回一個整型
% 取餘
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder
複製代碼

須要注意的是兩個整型相除是返回一個 double 類型的值,而不是像 Java 同樣返回一個整型,若是須要返回整型可使用 ~/ide

Dart 還支持前綴後綴自增自減操做符:函數

操做符 意義
++var var = var + 1 (整個表達式的值是 var + 1)
var++ var = var + 1 (整個表達式的值是 var)
--var var = var – 1 (整個表達式的值是 var – 1)
var-- var = var – 1 (整個表達式的值是 var)

下面的例子完美解釋了先後綴自增自減的差別:工具

var a, b;

a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1

a = 0;
b = a++; // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0

a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1

a = 0;
b = a--; // Decrement a AFTER b gets its value.
assert(a != b); // -1 != 0
複製代碼

比較操做符

操做符 意義
== 相等
!= 不等
> 大於
< 小於
>= 大於等於
<= 小於等於

須要注意的是,比較斷兩個對象內容是否相等使用 ==, 比較兩個對象是不是同一個對象使用 identical() 函數性能

比較兩個對象內容是否相等,須要重載操做符 == , 如何重載操做符後面會介紹學習

類型轉換和判斷操做符

操做符 意義
as 類型強轉
is 判斷某個對象是特定類型
is! 判斷某個對象不是特定類型
// 判斷 emp 是不是 Person 類型
if (emp is Person) {
  // Type check
  emp.firstName = 'Bob';
}


// 將 emp 強制轉換爲 Person, 若是 emp 不是 Person 類型則會拋出異常
(emp as Person).firstName = 'Bob';

複製代碼

邏輯操做符

操做符 意義
!expr 布爾取反
|| 邏輯或
&& 邏輯與
if (!done && (col == 0 || col == 3)) {
  // ...Do something...
}
複製代碼

位操做符

操做符 意義
& 按位與
| 按位或
^ 按位異或
~expr 按位非
<< 左移
>> 右移

賦值操做符

操做符 意義
= 賦值(a = b)
–= a -= b 和 a = a - b 等價
/= a /= b 和 a = a / b 等價
%= a %= b 和 a = a % b 等價
>>= a >>= b 和 a = a >> b 等價
^= a ^= b 和 a = a ^ b 等價
+= a += b 和 a = a + b 等價
*= a *= b 和 a = a * b 等價
~/= a ~/= b 和 a = a ~/ b 等價
<<= a <<= b 和 a = a << b 等價
&= a &= b 和 a = a & b 等價
|= a |= b 和 a = a | b 等價

條件表達式

Dart 提供了兩個操做符來簡化特定狀況的 if-else 語句開發工具

  • condition ? expr1 : expr2ui

    若是 condition 是 true, 返回 expr1, 不然返回 expr2

    var visibility = isPublic ? 'public' : 'private';
    複製代碼
  • expr1 ?? expr2

    若是 expr1 不爲 null, 返回 expr1, 不然返回 expr2

    String playerName(String name) => name ?? 'Guest';
    複製代碼

例如咱們能夠把下面的函數使用條件表達式簡化下:

String playerName(String name) {
  if (name != null) {
    return name;
  } else {
    return 'Guest';
  }
}

// 能夠簡化成以下:
String playerName(String name) => name != null ? name : 'Guest';
String playerName(String name) => name ?? 'Guest';

複製代碼

級聯符號(..)

嚴格的講, 級聯符號(cascade notation) 不是一個操做符, 而是 Dart 的一個語法糖, 它不只可讓開發者鏈式調用函數, 還能夠鏈式訪問屬性, 因此當咱們須要頻繁訪問某個對象的屬性和函數:

class Person {
  int age = 0;
  String name = "chiclaim";

  void sayHello() {
    print("hello , my name is $name");
  }
}

main(){
  var p = Person();
  p.age = 1;
  p.name = "johnny";
  p.sayHello();
}
複製代碼

咱們可使用級聯操做符改形成以下形勢:

main() {
  Person()
    ..age = 1
    ..name = "johnny"
    ..sayHello();
}
複製代碼

除此之外, 還能夠級聯嵌套, 如:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();
複製代碼

須要注意的是, 不能在一個 void 函數後面開始你的級聯操做:

var sb = StringBuffer();
sb.write('foo')
  ..write('bar');
複製代碼

可是能夠在調用 StringBuffer 構造函數後面開始你的級聯操做:

StringBuffer()
    ..write('foo')
    ..write('bar');
複製代碼

其餘操做符

操做符 意義
() 函數調用
[] 集合元素訪問
. 成員訪問
?. 成員訪問, 左邊的操做符能夠爲null, foo?.bar 若是 foo 爲空那麼整個表達式爲null

操做符重載

Dart 提供操做符重載功能,容許開發者重載一下操做符:

操做符 操做符 操做符 操做符
< + | []
> / ^ []=
<= ~/ & ~
>= * << ==
% >>

操做符重載的語法格式爲: 返回類型 operator 操做符 (參數)

下面來看下官方一個操做符重載的例子:

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);

  // 重載 == 操做符
  bool operator ==(other) => other is Vector 
        && runtimeType == other.runtimeType
        && x == other.x && y == other.y;

}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}

複製代碼

若是咱們重載了 == 操做符, 也要重載 hashCode 函數, 相似 Java 中重載了 equals 函數,最好也重載 hashCode 函數是同樣的, 由於對象的 hash 值決定對象的存儲位置

@override
int get hashCode => x.hashCode ^ y.hashCode;
複製代碼

控制流語句

if/else

Dart 支持 if 語句和可選的 else 語句

if (isRaining()) {
    print("raining");
} else if (isSnowing()) {
    print("snowing");
} else {
    print("unknown");
}
複製代碼

for循環

Dart 不只支持標準的 for 循環:

for (var i = 0; i < 5; i++) {
}
複製代碼

還支持 for-in 那些實現了 Iterator 接口的類(如List/Set):

var collection = [0, 1, 2];
for (var x in collection) {
  print(x); // 0 1 2
}
複製代碼

經過上一篇文章(三)Flutter學習之Dart函數的介紹知道

Dart Closures 可以訪問自身做用域內的變量, 哪怕這個變量是外部傳遞給 Closure 的 如:

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());

// 輸出
1
2
複製代碼

可是在 JavaScript 中會輸出兩個 2

while/do-while/break/continue

while/do-while/break/continue 和其餘語言沒有什麼區別, 在這裏就不贅述了

switch-case

Switch 語句能夠接受 整型、字符串 、枚舉 或者 編譯時常量, 而後使用 == 進行比較, 下面看下常量的比較:

class Person {
  final String id;

  const Person(this.id);
}

const p = Person("001");
const p1 = Person("001");
const p2 = Person("003");
  
switch (p) {
    case p1:
      print(p1.id);
      break;
    case p2:
      print(p2.id);
      break;
    default:
      print("unknown");
  }
複製代碼

若是 case 子句不是空, 要以 break/return/throw/continue 結尾, 不然會報錯

若是想要 case 子句之間 fall-through 的話, 將 case 子句爲空便可

var command = 'CLOSED';
  switch (command) {
    case 'CLOSED':
    case 'NOW_CLOSED':
      print("NOW_CLOSED");
      break;

    default:
      print("UNKNOWN");
  }
複製代碼

還可使用 continue 的方式 fall-through

var command = 'CLOSED';
switch (command) {
case 'CLOSED':
  print("CLOSED");
  continue nowClosed;

nowClosed:
case 'NOW_CLOSED':
  print("NOW_CLOSED");
  break;

default:
  print("UNKNOWN");
}

// 輸出

CLOSED
NOW_CLOSED

複製代碼

斷言(assert)

在開發階段, 咱們可使用斷言語句 assert(condition, optionalMessage); 來中斷程序的正常執行, 當 conditionfalse 的時候(拋出 AssertionError 異常); 若是 conditiontrue, 則繼續執行程序的下一行代碼. 例如:

// Make sure the value is less than 100.
assert(number < 100);

// Make sure this is an https URL.
assert(urlString.startsWith('https'));

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');
複製代碼

斷言何時生效呢?這取決於你使用的工具和框架:

  • Flutter 在 debug 模式啓用斷言
  • 僅開發階段使用的開發工具如 dartdevc, 默認是開啓斷言
  • 諸如 dartdart2js 等工具支持命令行來啓用斷言: --enable-asserts

在生產環境的代碼, 斷言語句將會被忽略, 斷言的 condition 表達式不會被執行,因此不用擔憂性能問題

異常處理

Dart 提供了 throw, rethrow, try, catch, on, finally 關鍵字讓開發者可以拋出和捕獲異常

Java 不一樣的是, Dart 中全部的異常都是 unchecked 異常, 也就是說編譯器不會強制開發者去捕獲任何異常, 除非你有這個須要

Dart 提供了兩個類異常: ExceptionError, Dart 不只能夠拋出異常還能夠拋出任何不爲 null 的對象:

// 拋出異常
throw FormatException('Expected at least 1 section');

// 拋出不爲 null 的對象
throw 'Out of llamas!';
複製代碼

雖然 Dart 容許咱們拋出一個不爲 null 的普通對象,可是官方仍是建議咱們拋出的異常繼承自 ExceptionError

介紹完了 throw 關鍵字,咱們來看下 catchon 和 關鍵字:

catchon 都是用來捕獲異常:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // 捕獲一個特定的異常
  buyMoreLlamas();
} on Exception catch (e) {
  // 捕獲全部繼承自 Exception 的異常,並拿到異常對象
  print('Unknown exception: $e');
} catch (e) {
  // 捕獲全部異常
  print('Something really unknown: $e');
}

複製代碼

可見, on 關鍵字用於指定捕獲特定的異常, catch 關鍵字用於拿到異常對象

catch 關鍵字除了能夠拿到異常對象, 還能夠拿到異常的 堆棧 信息, 如:

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

複製代碼

通常狀況下, 使用了 on, catch 關鍵字來捕獲異常, 異常會中止傳播, 若是須要異常繼續傳播可使用 rethrow 關鍵字

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // Runtime error
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // Allow callers to see the exception.
  }
}

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

複製代碼

最後介紹 Dart 異常處理的最後一個關鍵字 finally

finnaly 關鍵字很簡單 , 就是不論是否拋出異常 finally 子句必定會執行:

try {
  breedMoreLlamas();
} finally {
  // 就算拋出異常(程序中斷執行), finnaly 也會先執行
  cleanLlamaStalls();
}

try {
  breedMoreLlamas();
} catch (e) {
  // 捕獲異常
  print('Error: $e');
} finally {
  // 執行 finally 子句
  cleanLlamaStalls(); // Then clean up.
}
複製代碼

關於 Dart操做符, 控制流, 異常處理 就介紹完畢

Reference

dart.dev/guides/lang…

medium.com/@ayushpgupt…


聯繫我

下面是個人公衆號,乾貨文章不錯過,有須要的能夠關注下,有任何問題能夠聯繫我:

公衆號:  chiclaim
相關文章
相關標籤/搜索