Dart語法之變量聲明與數據類型實例詳解
前言
最近在學習做 flutter 移動端開發。相比 React-Native 開發而言, 使用 Flutter 開發的話要使用 Dart 這門語言,導致學習負擔更重一點。所以針對 Dart 語言的語法和使用做一下匯總。
以下內容參考自 Dart 官方文檔
1.安裝與使用
dart是由google公司開發的一門面向對象的編程語言。主要應用在移動端,配合 flutter
使用。dart2為現階段使用的穩定版本
1.1 安裝
因為學習 dart 大多數是為瞭寫 flutter,所以推薦直接下載 flutter,下載的 flutter 中會帶有 dart 的 SDK。
flutter 推薦去官網進行下載。下載完成後解壓,dart 的 SDK 就在解壓目錄\bin\cache\dart-sdk
下。
1.2 在 vscode 中使用
為瞭方便使用,我們可以將 dart 的 SDK 設置在環境變量中,將解壓目錄\bin\cache\dart-sdk\bin
的完整路徑設置好,在cmd 中輸入 dart ,有響應就代表設置成功瞭。
然後就是如何在 vscode 中使用dart。為瞭使用 dart,我需要下載兩個插件Dart
和Code Runner
,下載完成後創建一個文件main.dart
,輸入如下代碼:
// dart中的代碼需要放入main方法中執行 main(){ print('Hello World'); }
然後右鍵Run Code
,如果控制臺成功打印出Hello World
證明我們已經能夠在 vscode 中使用 dart 瞭。
2.類型聲明
2.1 變量聲明
在 dart 中有很多聲明變量的關鍵字,可以使用能接受任何類型值的變量申明(類似 JavaScript),也可以使用隻能接受固定類型值的變量聲明(類似 JAVA)。
2.1.1 var
類似於JavaScript中的var
,它可以接收任何類型的變量,但最大的不同是 dart 中var
變量一旦在聲明時被賦值(除瞭被賦值為 null,因為初始化的時候所有的值都為 null),類型便會確定,則不能再改變其類型,如:
var t = "hi world"; // 下面代碼在dart中會報錯,因為變量t的類型已經確定為String // 類型一旦確定後則不能再更改其類型 t = 1000;
💡 對於前端人員來說,其實看作是 TypeScript 的自動推斷類型的功能就好。
但是如果一開始沒有直接賦值,而是隻定義,那麼變量的類型默認會是dynamic
類型,也就說和 JavaScript 中的聲明的變量一樣的用法瞭。
var t; t = "hi world"; // 下面代碼在dart中不會報錯 t = 1000;
2.1.2 const 和 final
如果從未打算更改一個變量,那麼使用 final
或 const
,不是var
,也不是一個單獨的類型聲明(類型聲明也是可以更改值的,當使用類型聲明定義變量時,可以直接在前面加上const
或final
關鍵字使其變成常量,但是我們一般建議省略類型聲明)。
使用const
和final
聲明的變量都隻能被設置一次,兩者區別在於:
const
常量是一個編譯時常量(就是說必須要是一個在程序編譯時就完全固定的常量),final
常量不僅有const
的編譯時常量的特性,最重要的是它是運行時常量,final
是惰性初始化的,即在第一次使用時才會初始化。
// 可以省略String這個類型聲明 final str = "hi world"; final String sstr = "hi world"; const str1 = "hi world"; const String sstr1 = "hi world"; // 運行時常量在運行時才會被賦值 // 獲取當前時間,因為是動態獲取的,所以不能通過const聲明 final t = new DateTime.now(); // OK const t1 = new DateTime.now(); // Error
註意:
雖然 final 是運行時常量,第一次被賦值也必須是在定義的時候賦值。
final a; // Error a = 1;
實例變量可以是 final,但不能是 const。(實例變量定義在對象一級,它可以被類中的任何方法或者其他類中的方法訪問,但是不能被靜態方法訪問)
class A {} main() { final a = new A(); // OK const b = new A(); // Error }
const 關鍵字不隻是聲明常量變量。還可以使用它來創建常量值,以及聲明創建常量值的構造函數。任何變量都可以賦一個常量值。
var foo = const []; final bar = const []; // 可以從const聲明的初始化表達式中省略const const baz = []; // Equivalent to `const []` => const bar = const []; // 不能改變const變量的值 baz = [42]; // Error: Constant variables can't be assigned a value. // 可以更改一個非final的非const變量的值,即使它曾經有一個const值 foo = [1, 2, 3]; // Was const []
有些類提供常量構造函數。要使用常量構造函數創建編譯時常量,請將 const 關鍵字放在構造函數名之前:
class Person{ const Person(); } var p = const Person();
2.1.3 dynamic 和 Object
Object
是 dart 所有對象的根基類,也就是說所有類型都是Object
的子類(包括Function
和Null
),所以任何類型的數據都可以賦值給Object
聲明的對象。dynamic
是與int
這樣一樣的類型關鍵詞,改類型聲明的變量也可以賦值任意對象。
💡 dynamic
與Object
相同之處在於,它們聲明的變量可以在後期改變賦值類型(類似使用 JavaScript 或 TypeScript 中的any
類型)。
dynamic t; Object x; t = "hi world"; x = 'Hello Object'; // 下面代碼沒有問題 t = 1000; x = 1000;
dynamic
與Object
不同的是,dynamic
聲明的對象編譯器會提供所有可能的組合(也就是相當於就是完完全全的 JavaScript變量),而Object
聲明的對象隻能使用 Object 類的屬性與方法,否則編譯器會報錯。
dynamic a; Object b; main() { a = ""; b = ""; printLengths(); } printLengths() { // no warning print(a.length); // warning: // The getter 'length' is not defined for the class 'Object' print(b.length); }
2.1.4 默認值
未初始化的變量的初始值為 null。甚至具有數字類型的變量最初也是 null,因為在 dart 中所有的東西都是對象。
int lineCount; assert(lineCount == null);
註意: 在生產環境中,assert()
調用被忽略。在開發環境中當assert(condition)
的 condition 條件不為真時拋出一個異常。
2.2 數據類型
我們要清楚的是,dart 中的所有類型的值全都是對象,所以在其他語言中常用的基本類型聲明在 dart 中實質也是類的類型聲明。
2.2.1 Number
Number 總共能使用三種類型:
- num
- int
- double
Dart的數字有兩種形式:
int:根據平臺的不同,整數值不大於64位。在 Dart VM 上,值可以從-263
到263 - 1
。編譯成 JavaScript 的 Dart 使用 JavaScript 代碼,允許值從-253
到253 - 1
。
整數是沒有小數點的數。這裡有一些定義整數字面量的例子:
int x = 1; int hex = 0xDEADBEEF;
int 類型指定傳統的(<<, >>)和(&),或(|)
位操作符。例如:
assert((3 << 1) == 6); // 0011 << 1 == 0110 assert((3 >> 1) == 1); // 0011 >> 1 == 0001 assert((3 | 4) == 7); // 0011 | 0100 == 0111
double:64位(雙精度)浮點數,由IEEE 754標準指定。
如果一個數字包含一個小數,它就是一個雙精度數。這裡有一些定義雙精字面量的例子:
double y = 1.1; double exponents = 1.42e5;
註: int 和 double 都是 num 的子類型。num 類型包括基本的操作符,如+、-、/和*
,還可以在其中找到abs()、ceil()和floor()
等方法。(位運算符,如>>
,在int類中定義)如果 num 及其子類型沒有要查找的內容,那麼dart:math library
可能會有。
以下是如何將字符串轉換成數字的方法,反之亦然:
// String -> int var one = int.parse('1'); assert(one == 1); // String -> double var onePointOne = double.parse('1.1'); assert(onePointOne == 1.1); // int -> String String oneAsString = 1.toString(); assert(oneAsString == '1'); // double -> String String piAsString = 3.14159.toStringAsFixed(2); assert(piAsString == '3.14');
2.2.2 String
dart 字符串是 UTF-16 編碼單元的序列。可以使用單引號或雙引號創建一個字符串:
var s1 = 'Single quotes work well for string literals.'; var s2 = "Double quotes work just as well."; var s3 = 'It's easy to escape the string delimiter.'; var s4 = "It's even easier to use the other delimiter.";
可以使用${expression}
將表達式的值放入字符串中。如果表達式是一個標識符,可以跳過{}
。為瞭獲得與對象對應的字符串,dart 會自動調用對象的toString()方法。
var s = 'string interpolation'; assert('Dart has $s, which is very handy.' == 'Dart has string interpolation, ' + 'which is very handy.'); assert('That deserves all caps. ' + '${s.toUpperCase()} is very handy!' == 'That deserves all caps. ' + 'STRING INTERPOLATION is very handy!');
註意: ==檢驗兩個對象是否相等。如果兩個字符串包含相同序列的代碼單元,那麼它們是等價的,這點與 JavaScript 類似。
可以使用相鄰的字符串字面量(也可以看做是用空格) 或 + 運算符連接字符串:
var s1 = 'String ' 'concatenation' " works even over line breaks."; assert(s1 == 'String concatenation works even over ' 'line breaks.'); var s2 = 'The + operator ' + 'works, as well.'; assert(s2 == 'The + operator works, as well.');
對於創建多行字符串的方法:
- 使用
\n
用做換行。 - 使用帶有單引號或雙引號的三重引號。
var s = 'a \n multi-line string' var s1 = ''' You can create multi-line strings like this one. '''; var s2 = """This is also a multi-line string.""";
如果不想要轉義字符你可以用r
前綴創建一個原始字符串:
var s = r'In a raw string, not even \n gets special treatment.'; // In a raw string, not even \n gets special treatment.
要註意一點,字符串字面量是編譯時常量,隻要任何內插表達式都是編譯時常量,計算結果為 null 或數值、字符串或佈爾值。
// These work in a const string. const aConstNum = 0; const aConstBool = true; const aConstString = 'a constant string'; // These do NOT work in a const string. var aNum = 0; var aBool = true; var aString = 'a string'; const aConstList = [1, 2, 3]; const validConstString = '$aConstNum $aConstBool $aConstString'; // const invalidConstString = '$aNum $aBool $aString $aConstList'; // Error /* 前三個錯誤因為使用var進行申明的,var聲明的變量之後可以改變值,不符合常量定義,而後一個是因為不符合常量所需類型,也就是不符合null或數值、字符串或佈爾值。即使使用toString()方法也會報錯,這不符合編譯時常量的定義,除非用final */
2.2.3 Boolean
為瞭表示佈爾值,dart 有一個名為 bool 的類型。隻有兩個對象具有 bool 類型:佈爾字面量 true 和 false,它們都是編譯時常量。
dart 的類型安全性意味著不能使用if(非booleanvalue)
或assert(非booleanvalue)
之類的代碼。相反,顯式地檢查值,如:
// Check for an empty string. var fullName = ''; assert(fullName.isEmpty); // Check for zero. var hitPoints = 0; assert(hitPoints <= 0); // Check for null. var unicorn; assert(unicorn == null); // Check for NaN. var iMeantToDoThis = 0 / 0; assert(iMeantToDoThis.isNaN);
2.2.4 List
隻要 List、Set、Map 等的基本用法見 dart 常用庫的使用
Lst API 文檔
也許幾乎所有編程語言中最常見的集合就是數組或有序對象組。在 dart 中,數組是列表對象,所以大多數人把它們叫做列表。
dart 列表字面量看起來像 JavaScript 數組字面量。這是一個簡單的 dart 列表:
var list = [1, 2, 3];
註意: 上面的代碼分析器推斷該列表具有List<int>
類型。如果試圖向此列表添加非整型對象,則分析器或運行時將引發錯誤。
可以獲取列表的長度,並引用列表元素,就像在JavaScript中那樣:
var list = [1, 2, 3]; assert(list.length == 3); assert(list[1] == 2); list[1] = 1; assert(list[1] == 1);
要創建一個編譯時常量列表(不能再之後改變值),需要在列表字面量之前添加 const(或者直接使用 const 申明變量):
var constantList = const [1, 2, 3]; // OR const constantList = [1, 2, 3]; // constantList[1] = 1; // Uncommenting this causes an error. // 這裡不會在編譯時報錯,但是運行時會拋出異常
列表類型有許多便於操作列表的方法,在這裡不說,在之後會進行詳細說明。
2.2.5 Set
Set API 文檔
dart 中的集合是一組無序的獨特物品集合。因為集合是無序的,所以不能通過索引(位置)獲得集合的項。
var ingredients = Set(); ingredients.addAll(['gold', 'titanium', 'xenon']); assert(ingredients.length == 3); // Adding a duplicate item has no effect. ingredients.add('gold'); assert(ingredients.length == 3); // Remove an item from a set. ingredients.remove('gold'); assert(ingredients.length == 2);
使用contains()
和containsAll()
來檢查集合中是否有一個或多個對象:
var ingredients = Set(); ingredients.addAll(['gold', 'titanium', 'xenon']); // Check whether an item is in the set. assert(ingredients.contains('titanium')); // Check whether all the items are in the set. assert(ingredients.containsAll(['titanium', 'xenon']));
交集是一個集合,其項在另外兩個集合中:
var ingredients = Set(); ingredients.addAll(['gold', 'titanium', 'xenon']); // Create the intersection of two sets. var nobleGases = Set.from(['xenon', 'argon']); var intersection = ingredients.intersection(nobleGases); assert(intersection.length == 1); assert(intersection.contains('xenon'));
2.2.6 Map
Map API 文檔
通常,map 是一個關聯鍵和值的對象。鍵和值都可以是任何類型的對象。每個鍵隻出現一次,但是您可以多次使用相同的值。dart 對 map 的支持是通過 map 字面量和 map 類型來提供的。(可以看做是混入瞭 JavaScript 對象字面量寫法和 JAVA 的 HashMap 鍵值的對象)
var gifts = { // Key: Value 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' }; var nobleGases = { 2: 'helium', 10: 'neon', 18: 'argon', };
註意:
在上面的代碼中,解析器推斷 gifts 的類型為Map<String, String>
,nobleGases 的類型為Map<int, String>
。如果您試圖向 map 添加錯誤類型的值,則分析器或運行時將引發錯誤。
dart 中的 map 和 JavaScript 中的對象是有區別的,鍵(key)可以是任意數據類型,並且如果是 String 類型的話不能省略引號,因為在 dart 中這樣會將其解析為一個變量。
const a = '1'; var map1 = { true: '123', a: '2', // 不加引號的a會被解析為'1' b: '2', // 報錯,沒有b變量 'a': '2' };
同樣的,在通過 map 的鍵獲取值得時候,不能使用 JavaScript 中常見的點(.)
操作符,隻能使用[]
操作符,點(.)
操作符隻能用在獲取 dart 中通過類生成的對象的屬性或方法中(因為 map 生成的自變量隻是看起來和 JavaScript 中的一樣,實際上還是有很大差別的) 。
同樣可以使用Map構造函數創建對象:
var gifts = new Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings'; var nobleGases = new Map(); nobleGases[2] = 'helium'; nobleGases[10] = 'neon'; nobleGases[18] = 'argon';
添加值和檢索值都如同 JavaScript 中那樣進行,不同的是:
如果要獲取的鍵不再 map 中,將會返回一個 null:
var gifts = {'first': 'partridge'}; assert(gifts['fifth'] == null);
可以使用.length
獲取 map 中元素的個數:
var gifts = {'first': 'partridge'}; gifts['fourth'] = 'calling birds'; assert(gifts.length == 2);
要創建一個編譯時常量的 map 需要在 map 的字面量前加const
關鍵字(或直接使用 const 聲明的變量):
var constantMap = const { 2: 'helium', 10: 'neon', 18: 'argon', }; // OR const constantMap = { 2: 'helium', 10: 'neon', 18: 'argon', }; // constantMap[2] = 'Helium'; // Uncommenting this causes an error. // 這裡不會在編譯時報錯,但是運行時會拋出異常
2.2.7 Runes(字符)
在 dart 中,字符是字符串的UTF-32編碼點。
Unicode 為世界上所有的書寫系統中使用的每個字母、數字和符號定義一個唯一的數值。因為 dart 字符串是 UTF-16 代碼單元的序列,所以在字符串中表示32位的 Unicode 值需要特殊的語法。
表示 Unicode 碼點的常用方法是\uXXXX
,其中 XXXX 是4位數的十六進制值。例如,心型字符(♥)的編碼為\u2665
。要指定大於或小於4位十六進制數字,請將值放在花括號中。例如笑臉表情(😆)的編碼\u{1f600}
。
String 類有幾個屬性可以用來獲取 runes信息。codeUnitAt 和 codeUnit 屬性返回16位代碼單元。使用字符屬性獲取字符串的字符。
下面的示例說明瞭字符、16位代碼單元和32位代碼點之間的關系:
main() { var clapping = '\u{1f600}'; print(clapping); print(clapping.codeUnits); print(clapping.runes.toList()); Runes input = new Runes( '\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}'); print(new String.fromCharCodes(input)); } //運行效果如下 😀 [55357, 56832] [128512] ♥ 😅 😎 👻 🖖 👍 Process finished with exit code 0
註意: 使用列表操作操作 runes 時要小心。根據特定的語言、字符集和操作,這種方法很容易出錯。有關更多信息,請參見如何在Dart中反轉字符串?
2.2.8 Symbols(符號)
符號對象表示在 dart 程序中聲明的操作符或標識符。一般來說可能永遠不需要使用符號,但是對於按名稱引用標識符的api 來說,它們是非常重要的,因為縮小改變瞭標識符名稱而不是標識符符號。
要獲取標識符的符號,請使用符號文字,符號文字僅為#
,後面跟著標識符:
#radix #bar
註意: 符號常量是編譯時常量。
2.2.9 枚舉類型
枚舉類型可以看做是 dart 對類(class)的一種延伸。
使用enum
關鍵字聲明一個枚舉類型:
enum Color { red, green, blue }
枚舉中的每個值都有一個索引 getter,它返回enum
聲明中值的從0開始的位置。例如,第一個值有索引0,第二個值有索引1。
assert(Color.red.index == 0); assert(Color.green.index == 1); assert(Color.blue.index == 2);
使用enum
的values
常量要獲取枚舉中所有值的列表。
List<Color> colors = Color.values; assert(colors[2] == Color.blue);
可以在 switch 語句中使用enum
,如果 switch 的 case 不處理enum
的所有值,將會報一個警告消息:
var aColor = Color.blue; switch (aColor) { case Color.red: print('Red as roses!'); break; case Color.green: print('Green as grass!'); break; default: // Without this, you see a WARNING. print(aColor); // 'Color.blue' }
枚舉類型有以下限制:
- 不能子類化、混合或實現枚舉。
- 不能顯式實例化一個枚舉。
以上就是Dart語法之變量聲明與數據類型實例詳解的詳細內容,更多關於Dart變量聲明數據類型的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Android開發Dart Constructors構造函數使用技巧整理
- Flutter 給列表增加下拉刷新和上滑加載更多功能
- flutter封裝單選點擊菜單工具欄組件
- Flutter路由之fluro的配置及跳轉
- Flutter路由fluro引入配置和使用的具體方法