三種運算子總覽(as / is / is!)
| 運算子 | 功能說明 |
|---|---|
as | 型別強制轉換;亦可用於程式庫前綴別名限定 |
is | 型別判斷:物件屬於指定型別時回傳 true |
is! | 型別判斷:物件不屬於指定型別時回傳 true |
obj is T 成立條件:物件 obj 實作 / 繼承型別 T(包含父類別、介面、可空型別)。
舉例來說 任意物件 is Object? 永遠為 true。
is 運算子
安全型別判斷
判斷物件執行期型別;若判斷結果為 true,程式區塊內可直接以該型別操作,不需手動強制轉型;若物件為 null 或型別不符,直接回傳 false,不會拋出例外。
下方範例使用類別物件,讀者若尚未學到類別,可先將其理解為用來封裝資料的資料模型。
class Person {
String firstName = '';
}
class Employee extends Person {}
void main() {
dynamic employee = Employee();
// 使用 is 判斷型別
if (employee is Person) {
// 進入判斷分支後,employee 自動推斷為 Person 型別
employee.firstName = "Jack";
print(employee.firstName); // 輸出 Jack
}
dynamic emptyObj = null;
if (emptyObj is Person) {
// 不會執行,null 不匹配 Person 型別
print("比對成功");
}
}Code language: Dart (dart)
以上程式定義 Person 類別,再建立 Employee 類別並繼承 Person。
程式中透過 is 判斷物件是否為 Person,若成立,在大括號區塊內就能直接當作 Person 操作。此處變數採用 dynamic 動態型別宣告:dynamic employee = Employee();。
第二個範例 dynamic emptyObj = null;,因為變數值為 null,因此 emptyObj is Person 結果為 false,大括號內程式不會執行。
is! 運算子
反向型別判斷
語法:
變數 is! 型別
實際等同於先用 is 判斷後再取反。
等價寫法:!(變數 is 型別),用來判斷物件不屬於目標型別。
參考範例:
class Person {
String name = '';
}
void main() {
dynamic obj = "文字";
if (obj is! Person) {
print("obj 不是 Person 型別");
}
}Code language: Dart (dart)
上述範例會執行大括號內程式,輸出「obj 不是 Person 型別」,因為 obj 並非透過 Person 類別建立的實體。
as 運算子
強制型別轉換
使用方式:
(變數 as 目標型別).屬性/方法Code language: JavaScript (javascript)
僅建議在你百分之百確認物件就是目標型別時使用,否則會拋出執行期例外。為維持程式穩健性,不建議大量使用。
class Teacher {
String name = '';
}
void main() {
dynamic jason = Teacher();
// 強制轉型為 Teacher 後存取屬性
(jason as Teacher).name = "Jason";
print((jason as Teacher).name); // Jason
}Code language: Dart (dart)
以上範例輸出 Jason
我們透過 dynamic jason = Teacher(); 建立 Teacher 實體,能完全確認該物件型別為 Teacher,因此這段轉換不會報錯。

若像下方這樣撰寫,就會發生錯誤。
class Teacher {
String name = '';
}
class Car {
String name = '';
}
void main() {
dynamic jason = Teacher();
// 強制轉型為 Car 後存取屬性
(jason as Car).name = "Jason";//❌錯誤
print((jason as Car).name); //❌錯誤
}Code language: Dart (dart)
因為 jason 本身是 Teacher 實體,卻強制轉換為 Car,執行時會報錯。
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
type 'Teacher' is not a subtype of type 'Car' in type cast
#0 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:12:10)
#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)
as 與 is 核心差異比較
// 寫法1:as 強制轉型
(employee as Person).firstName = 'Bob';
// 寫法2:先用 is 判斷再操作
if (employee is Person) {
employee.firstName = 'Bob';
}Code language: JavaScript (javascript)
當 employee 為 null 或不屬於 Person 型別時:
as寫法:直接拋出CastError,程式中斷;is寫法:不會進入 if 區塊,程式無錯誤、不執行任何操作。
因此優先使用 is 判斷的寫法,雖然程式碼會多幾行,但程式穩健度更高。
as 的第二種用途
as 的第二種用途
as 除了型別轉換,匯入程式庫時還能替程式庫設定別名
import 'dart:math' as math;
void main() {
// 透過程式庫別名呼叫類別/方法
print(math.pi); //輸出 3.141592653589793
}Code language: JavaScript (javascript)
完整綜合範例
class Animal {}
class Cat extends Animal {}
void main() {
dynamic obj = Cat();
// 1. is 正向判斷
if (obj is Animal) {
print("obj 是 Animal 型別");
}
// 2. is! 反向判斷
if (obj is! String) {
print("obj 不是字串");
}
// 3. as 強制轉型
Animal a = obj as Animal;
// 錯誤示範,執行會崩潰
dynamic str = "hello";
// Animal error = str as Animal; // CastError
}Code language: JavaScript (javascript)