# [Branches](https://dart.dev/language/branches) * If * If-case * [Conditional expressions](https://dart.dev/language/operators#conditional-expressions) * Switch statements * [Switch expressions](https://www.christianfindlay.com/blog/dart-switch-expressions) * Exhaustiveness checking 詳盡性檢查(就是要寫死) * Guard clause # [Exceptions](https://dart.dev/language/error-handling) * Exception, Error, any not null obj * throw, rethrow * on xx catch e * finally * Assert ## if ``` String s = 'https://hackmd.io/'; if (s.startsWith('http')) { print('it is a http url'); } else if (s.startsWith('ftp')) { print("it's a ftp url"); } else { print("it's not an url"); } ``` ## If-case if-case 語句提供了一種針對單一模式進行匹配和解構的方法。若要針對多種模式測試某個值,請使用switch, 匹配成功為真. ``` List<int> pair = [12, 23]; if (pair case [int x, int y]) { print('Was coordinate array $x,$y'); } else { throw FormatException('Invalid coordinates.'); } ``` ## if 三元運算 ``` int a = 5; int b = 10; // 使用三元运算符 String result = a > b ? 'a大于b' : 'a不大于b'; print(result); // 使用 if 的简写形式 String message = if (a > b) 'a大于b' else 'a不大于b'; ``` ## if 運用在List ``` bool isLoggedIn = true; List<String> menuItems = [ '首页', '个人资料', if (isLoggedIn) '退出登录' else '登录', '设置' ]; print(menuItems); // [首页, 个人资料, 退出登录, 设置] ``` ``` bool isLoggedIn = false; List<String> menuItems = [ '首页', '个人资料', if (isLoggedIn) '退出登录' , '设置' ]; print(menuItems); // [首页, 个人资料, 设置] ``` ## if 運用在Map ``` bool includeDetails = true; var userInfo = { 'name': '张三', 'age': 25, if (includeDetails) 'email': 'zhangsan@example.com', if (includeDetails) 'phone': '123-456-7890' }; print(userInfo); // {name: 张三, age: 25, email: zhangsan@example.com, phone: 123-456-7890} ``` ``` bool includeDetails = true; var userInfo = { 'name': '张三', 'age': 25, if (includeDetails) 'email': 'zhangsan@example.com' else 'phone':'0935859966' }; print(userInfo); ``` ## Conditional expressions * condition?a:b * a??b ``` var visibility = isPublic ? 'public' : 'private'; String playerName(String? name) => name ?? 'Guest'; // if-null operator ``` ## Switch statements 當沒有case子句匹配時,使用default或通配符_執行程式碼 空的case被匹配到時, 會執行下一個case ``` int c = 12; switch (c) { case 12: case 13: print('13 or 12'); default: print('not match'); } // 印出 13 or 12 ``` continue會直接執行label處的case然後停止 ``` int number = 2; switch (number) { case 1: print('Case 1'); case 2: print('Case 2, falling through to case 3'); continue label; // Continue to case 3 case 3: print('Case 3'); label: case 4: print('Case 4'); default: print('Default case'); } ``` ``` List<int> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (int number in numbers) { switch (number) { case 3: case 4: print('Skipping $number'); continue; // Skip the rest of this iteration case 6: print('Special case for $number'); break; // Exit the switch and continue the loop default: print('Processing $number'); } } ``` ## Switch expressions 能夠使用expression的地方都可以使用 ``` var x = switch (y) { ... }; print(switch (x) { ... }); return switch (x) { ... }; ``` ``` // Where slash, star, comma, semicolon, etc., are constant variables... token = switch (charCode) { slash || star || plus || minus => operator(charCode), comma || semicolon => punctuation(charCode), >= digit0 && <= digit9 => number(), _ => throw FormatException('Invalid') }; ``` ## Exhaustiveness checking 就是比對值進入switch後一定要有比對到, 否則報錯 ex. 如果有人新增Shape的子類型, 則switch expression會檢查出來 ``` import 'dart:math'; sealed class Shape {} class Square implements Shape { final double length; Square(this.length); } class Circle implements Shape { final double radius; Circle(this.radius); } double calculateArea(Shape shape) => switch (shape) { Square(length: var l) => l * l, Circle(radius: var r) => pi * r * r }; void main() { Shape c = Circle(5); print(calculateArea((c))); } ``` ## Guard clause 就是多增加限制條件, if-case或switch statement或expression都可以有,當保護子句的計算結果為 false 時,將繼續執行下一個 case,而不是退出switch ``` class Person { String name; int age; int yearExoerience; Person(this.name, this.age, this.yearExoerience); } void main() { List stuff = [ Person('John', 23, 3), Person('Mary', 29, 2), Person('Bob', 35, 4), 123, 456, true ]; for (var p in stuff) { switch (p) { case Person(name: var n, age: var a, yearExoerience: var y) when a <= 30 && a > 20: print('${n} is young, his yearExoerience is $y'); break; case Person(name: var n, age: var a, yearExoerience: var y) when a > 30: print('$n is over 30 yo.'); } } print('----------------'); for (var p in stuff) { String ret = switch (p) { Person(name: var n, age: var a, yearExoerience: var y) when a <= 30 && a > 20 => "${n} is young, his yearExoerience is $y", Person(name: var n, age: var a, yearExoerience: var y) when a > 30 => '$n is over 30 yo.', _ => '' }; print(ret); } } ``` ## [Exceptions](https://dart.dev/language/error-handling) Dart 提供了[Exception](https://api.dart.dev/stable/3.5.1/dart-core/Exception-class.html)和[Error](https://api.dart.dev/stable/3.5.1/dart-core/Error-class.html)類型,以及其預先定義的子類型。Dart 程式可以拋出任何非 null 物件作為異常。 ``` throw FormatException('Expected at least 1 section'); // 拋出任意非null物件 throw 'Out of llamas!'; // throw 是個expression void distanceTo(Point other) => throw UnimplementedError(); ``` catch綜合範例 ``` try { // ··· } on FormatException { // 捕捉指定的異常 } on Exception catch (e) { // 捕捉所有Exception類 print('Exception details:\n $e') } catch (e) { // 捕捉所有非null異常物件 print('Something really unknown: $e'); } catch (e, s) { // s 是堆疊追蹤 print('Exception details:\n $e'); print('Stack trace:\n $s'); } finally { // 一定會執行 } ``` rethrow 希望異常繼續傳播 ``` void misbehave() { try { dynamic foo = true; print(foo++); // Runtime error } catch (e) { // 初步處理異常 print('misbehave() partially handled ${e.runtimeType}.'); // 讓main()也取得異常 rethrow; } } void main() { try { misbehave(); } catch (e) { print('main() finished handling ${e.runtimeType}.'); } } ``` Assert ` assert(<condition>, <optionalMessage>);` condition==false時會中斷程式執行 ``` assert(text != null); assert(number < 100,'$number is bigger than 100'); assert(urlString.startsWith('https')); ```