Dart語法之變量聲明與數(shù)據(jù)類型實(shí)例詳解
前言
最近在學(xué)習(xí)做 flutter 移動(dòng)端開發(fā)。相比 React-Native 開發(fā)而言, 使用 Flutter 開發(fā)的話要使用 Dart 這門語言,導(dǎo)致學(xué)習(xí)負(fù)擔(dān)更重一點(diǎn)。所以針對(duì) Dart 語言的語法和使用做一下匯總。
以下內(nèi)容參考自 Dart 官方文檔
1.安裝與使用
dart是由google公司開發(fā)的一門面向?qū)ο蟮木幊陶Z言。主要應(yīng)用在移動(dòng)端,配合 flutter
使用。dart2為現(xiàn)階段使用的穩(wěn)定版本
1.1 安裝
因?yàn)閷W(xué)習(xí) dart 大多數(shù)是為了寫 flutter,所以推薦直接下載 flutter,下載的 flutter 中會(huì)帶有 dart 的 SDK。
flutter 推薦去官網(wǎng)進(jìn)行下載。下載完成后解壓,dart 的 SDK 就在解壓目錄\bin\cache\dart-sdk
下。
1.2 在 vscode 中使用
為了方便使用,我們可以將 dart 的 SDK 設(shè)置在環(huán)境變量中,將解壓目錄\bin\cache\dart-sdk\bin
的完整路徑設(shè)置好,在cmd 中輸入 dart ,有響應(yīng)就代表設(shè)置成功了。
然后就是如何在 vscode 中使用dart。為了使用 dart,我需要下載兩個(gè)插件Dart
和Code Runner
,下載完成后創(chuàng)建一個(gè)文件main.dart
,輸入如下代碼:
// dart中的代碼需要放入main方法中執(zhí)行 main(){ print('Hello World'); }
然后右鍵Run Code
,如果控制臺(tái)成功打印出Hello World
證明我們已經(jīng)能夠在 vscode 中使用 dart 了。
2.類型聲明
2.1 變量聲明
在 dart 中有很多聲明變量的關(guān)鍵字,可以使用能接受任何類型值的變量申明(類似 JavaScript),也可以使用只能接受固定類型值的變量聲明(類似 JAVA)。
2.1.1 var
類似于JavaScript中的var
,它可以接收任何類型的變量,但最大的不同是 dart 中var
變量一旦在聲明時(shí)被賦值(除了被賦值為 null,因?yàn)槌跏蓟臅r(shí)候所有的值都為 null),類型便會(huì)確定,則不能再改變其類型,如:
var t = "hi world"; // 下面代碼在dart中會(huì)報(bào)錯(cuò),因?yàn)樽兞縯的類型已經(jīng)確定為String // 類型一旦確定后則不能再更改其類型 t = 1000;
?? 對(duì)于前端人員來說,其實(shí)看作是 TypeScript 的自動(dòng)推斷類型的功能就好。
但是如果一開始沒有直接賦值,而是只定義,那么變量的類型默認(rèn)會(huì)是dynamic
類型,也就說和 JavaScript 中的聲明的變量一樣的用法了。
var t; t = "hi world"; // 下面代碼在dart中不會(huì)報(bào)錯(cuò) t = 1000;
2.1.2 const 和 final
如果從未打算更改一個(gè)變量,那么使用 final
或 const
,不是var
,也不是一個(gè)單獨(dú)的類型聲明(類型聲明也是可以更改值的,當(dāng)使用類型聲明定義變量時(shí),可以直接在前面加上const
或final
關(guān)鍵字使其變成常量,但是我們一般建議省略類型聲明)。
使用const
和final
聲明的變量都只能被設(shè)置一次,兩者區(qū)別在于:
const
常量是一個(gè)編譯時(shí)常量(就是說必須要是一個(gè)在程序編譯時(shí)就完全固定的常量),final
常量不僅有const
的編譯時(shí)常量的特性,最重要的是它是運(yùn)行時(shí)常量,final
是惰性初始化的,即在第一次使用時(shí)才會(huì)初始化。
// 可以省略String這個(gè)類型聲明 final str = "hi world"; final String sstr = "hi world"; const str1 = "hi world"; const String sstr1 = "hi world"; // 運(yùn)行時(shí)常量在運(yùn)行時(shí)才會(huì)被賦值 // 獲取當(dāng)前時(shí)間,因?yàn)槭莿?dòng)態(tài)獲取的,所以不能通過const聲明 final t = new DateTime.now(); // OK const t1 = new DateTime.now(); // Error
注意:
雖然 final 是運(yùn)行時(shí)常量,第一次被賦值也必須是在定義的時(shí)候賦值。
final a; // Error a = 1;
實(shí)例變量可以是 final,但不能是 const。(實(shí)例變量定義在對(duì)象一級(jí),它可以被類中的任何方法或者其他類中的方法訪問,但是不能被靜態(tài)方法訪問)
class A {} main() { final a = new A(); // OK const b = new A(); // Error }
const 關(guān)鍵字不只是聲明常量變量。還可以使用它來創(chuàng)建常量值,以及聲明創(chuàng)建常量值的構(gòu)造函數(shù)。任何變量都可以賦一個(gè)常量值。
var foo = const []; final bar = const []; ? // 可以從const聲明的初始化表達(dá)式中省略const const baz = []; // Equivalent to `const []` => const bar = const []; // 不能改變const變量的值 baz = [42]; // Error: Constant variables can't be assigned a value. // 可以更改一個(gè)非final的非const變量的值,即使它曾經(jīng)有一個(gè)const值 foo = [1, 2, 3]; // Was const []
有些類提供常量構(gòu)造函數(shù)。要使用常量構(gòu)造函數(shù)創(chuàng)建編譯時(shí)常量,請(qǐng)將 const 關(guān)鍵字放在構(gòu)造函數(shù)名之前:
class Person{ const Person(); } var p = const Person();
2.1.3 dynamic 和 Object
Object
是 dart 所有對(duì)象的根基類,也就是說所有類型都是Object
的子類(包括Function
和Null
),所以任何類型的數(shù)據(jù)都可以賦值給Object
聲明的對(duì)象。dynamic
是與int
這樣一樣的類型關(guān)鍵詞,改類型聲明的變量也可以賦值任意對(duì)象。
?? dynamic
與Object
相同之處在于,它們聲明的變量可以在后期改變賦值類型(類似使用 JavaScript 或 TypeScript 中的any
類型)。
dynamic t; Object x; t = "hi world"; x = 'Hello Object'; // 下面代碼沒有問題 t = 1000; x = 1000;
dynamic
與Object
不同的是,dynamic
聲明的對(duì)象編譯器會(huì)提供所有可能的組合(也就是相當(dāng)于就是完完全全的 JavaScript變量),而Object
聲明的對(duì)象只能使用 Object 類的屬性與方法,否則編譯器會(huì)報(bào)錯(cuò)。
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 默認(rèn)值
未初始化的變量的初始值為 null。甚至具有數(shù)字類型的變量最初也是 null,因?yàn)樵?dart 中所有的東西都是對(duì)象。
int lineCount; assert(lineCount == null);
注意: 在生產(chǎn)環(huán)境中,assert()
調(diào)用被忽略。在開發(fā)環(huán)境中當(dāng)assert(condition)
的 condition 條件不為真時(shí)拋出一個(gè)異常。
2.2 數(shù)據(jù)類型
我們要清楚的是,dart 中的所有類型的值全都是對(duì)象,所以在其他語言中常用的基本類型聲明在 dart 中實(shí)質(zhì)也是類的類型聲明。
2.2.1 Number
Number 總共能使用三種類型:
- num
- int
- double
Dart的數(shù)字有兩種形式:
int:根據(jù)平臺(tái)的不同,整數(shù)值不大于64位。在 Dart VM 上,值可以從-263
到263 - 1
。編譯成 JavaScript 的 Dart 使用 JavaScript 代碼,允許值從-253
到253 - 1
。
整數(shù)是沒有小數(shù)點(diǎn)的數(shù)。這里有一些定義整數(shù)字面量的例子:
int x = 1; int hex = 0xDEADBEEF;
int 類型指定傳統(tǒng)的(<<, >>)和(&),或(|)
位操作符。例如:
assert((3 << 1) == 6); // 0011 << 1 == 0110 assert((3 >> 1) == 1); // 0011 >> 1 == 0001 assert((3 | 4) == 7); // 0011 | 0100 == 0111
double:64位(雙精度)浮點(diǎn)數(shù),由IEEE 754標(biāo)準(zhǔn)指定。
如果一個(gè)數(shù)字包含一個(gè)小數(shù),它就是一個(gè)雙精度數(shù)。這里有一些定義雙精字面量的例子:
double y = 1.1; double exponents = 1.42e5;
注: int 和 double 都是 num 的子類型。num 類型包括基本的操作符,如+、-、/和*
,還可以在其中找到abs()、ceil()和floor()
等方法。(位運(yùn)算符,如>>
,在int類中定義)如果 num 及其子類型沒有要查找的內(nèi)容,那么dart:math library
可能會(huì)有。
以下是如何將字符串轉(zhuǎn)換成數(shù)字的方法,反之亦然:
// 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 編碼單元的序列??梢允褂脝我?hào)或雙引號(hào)創(chuàng)建一個(gè)字符串:
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}
將表達(dá)式的值放入字符串中。如果表達(dá)式是一個(gè)標(biāo)識(shí)符,可以跳過{}
。為了獲得與對(duì)象對(duì)應(yīng)的字符串,dart 會(huì)自動(dòng)調(diào)用對(duì)象的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!');
注意: ==檢驗(yàn)兩個(gè)對(duì)象是否相等。如果兩個(gè)字符串包含相同序列的代碼單元,那么它們是等價(jià)的,這點(diǎn)與 JavaScript 類似。
可以使用相鄰的字符串字面量(也可以看做是用空格) 或 + 運(yùn)算符連接字符串:
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.');
對(duì)于創(chuàng)建多行字符串的方法:
- 使用
\n
用做換行。 - 使用帶有單引號(hào)或雙引號(hào)的三重引號(hào)。
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.""";
如果不想要轉(zhuǎn)義字符你可以用r
前綴創(chuàng)建一個(gè)原始字符串:
var s = r'In a raw string, not even \n gets special treatment.'; // In a raw string, not even \n gets special treatment.
要注意一點(diǎn),字符串字面量是編譯時(shí)常量,只要任何內(nèi)插表達(dá)式都是編譯時(shí)常量,計(jì)算結(jié)果為 null 或數(shù)值、字符串或布爾值。
// 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 /* 前三個(gè)錯(cuò)誤因?yàn)槭褂胿ar進(jìn)行申明的,var聲明的變量之后可以改變值,不符合常量定義,而后一個(gè)是因?yàn)椴环铣A克桀愋停簿褪遣环蟦ull或數(shù)值、字符串或布爾值。即使使用toString()方法也會(huì)報(bào)錯(cuò),這不符合編譯時(shí)常量的定義,除非用final */
2.2.3 Boolean
為了表示布爾值,dart 有一個(gè)名為 bool 的類型。只有兩個(gè)對(duì)象具有 bool 類型:布爾字面量 true 和 false,它們都是編譯時(shí)常量。
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 常用庫(kù)的使用
也許幾乎所有編程語言中最常見的集合就是數(shù)組或有序?qū)ο蠼M。在 dart 中,數(shù)組是列表對(duì)象,所以大多數(shù)人把它們叫做列表。
dart 列表字面量看起來像 JavaScript 數(shù)組字面量。這是一個(gè)簡(jiǎn)單的 dart 列表:
var list = [1, 2, 3];
注意: 上面的代碼分析器推斷該列表具有List<int>
類型。如果試圖向此列表添加非整型對(duì)象,則分析器或運(yùn)行時(shí)將引發(fā)錯(cuò)誤。
可以獲取列表的長(zhǎng)度,并引用列表元素,就像在JavaScript中那樣:
var list = [1, 2, 3]; assert(list.length == 3); assert(list[1] == 2); list[1] = 1; assert(list[1] == 1);
要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量列表(不能再之后改變值),需要在列表字面量之前添加 const(或者直接使用 const 申明變量):
var constantList = const [1, 2, 3]; // OR const constantList = [1, 2, 3]; // constantList[1] = 1; // Uncommenting this causes an error. // 這里不會(huì)在編譯時(shí)報(bào)錯(cuò),但是運(yùn)行時(shí)會(huì)拋出異常
列表類型有許多便于操作列表的方法,在這里不說,在之后會(huì)進(jìn)行詳細(xì)說明。
2.2.5 Set
dart 中的集合是一組無序的獨(dú)特物品集合。因?yàn)榧鲜菬o序的,所以不能通過索引(位置)獲得集合的項(xiàng)。
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()
來檢查集合中是否有一個(gè)或多個(gè)對(duì)象:
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']));
交集是一個(gè)集合,其項(xiàng)在另外兩個(gè)集合中:
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 是一個(gè)關(guān)聯(lián)鍵和值的對(duì)象。鍵和值都可以是任何類型的對(duì)象。每個(gè)鍵只出現(xiàn)一次,但是您可以多次使用相同的值。dart 對(duì) map 的支持是通過 map 字面量和 map 類型來提供的。(可以看做是混入了 JavaScript 對(duì)象字面量寫法和 JAVA 的 HashMap 鍵值的對(duì)象)
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 添加錯(cuò)誤類型的值,則分析器或運(yùn)行時(shí)將引發(fā)錯(cuò)誤。
dart 中的 map 和 JavaScript 中的對(duì)象是有區(qū)別的,鍵(key)可以是任意數(shù)據(jù)類型,并且如果是 String 類型的話不能省略引號(hào),因?yàn)樵?dart 中這樣會(huì)將其解析為一個(gè)變量。
const a = '1'; var map1 = { true: '123', a: '2', // 不加引號(hào)的a會(huì)被解析為'1' b: '2', // 報(bào)錯(cuò),沒有b變量 'a': '2' };
同樣的,在通過 map 的鍵獲取值得時(shí)候,不能使用 JavaScript 中常見的點(diǎn)(.)
操作符,只能使用[]
操作符,點(diǎn)(.)
操作符只能用在獲取 dart 中通過類生成的對(duì)象的屬性或方法中(因?yàn)?map 生成的自變量只是看起來和 JavaScript 中的一樣,實(shí)際上還是有很大差別的) 。
同樣可以使用Map構(gòu)造函數(shù)創(chuàng)建對(duì)象:
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 中那樣進(jìn)行,不同的是:
如果要獲取的鍵不再 map 中,將會(huì)返回一個(gè) null:
var gifts = {'first': 'partridge'}; assert(gifts['fifth'] == null);
可以使用.length
獲取 map 中元素的個(gè)數(shù):
var gifts = {'first': 'partridge'}; gifts['fourth'] = 'calling birds'; assert(gifts.length == 2);
要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量的 map 需要在 map 的字面量前加const
關(guān)鍵字(或直接使用 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. // 這里不會(huì)在編譯時(shí)報(bào)錯(cuò),但是運(yùn)行時(shí)會(huì)拋出異常
2.2.7 Runes(字符)
在 dart 中,字符是字符串的UTF-32編碼點(diǎn)。
Unicode 為世界上所有的書寫系統(tǒng)中使用的每個(gè)字母、數(shù)字和符號(hào)定義一個(gè)唯一的數(shù)值。因?yàn)?dart 字符串是 UTF-16 代碼單元的序列,所以在字符串中表示32位的 Unicode 值需要特殊的語法。
表示 Unicode 碼點(diǎn)的常用方法是\uXXXX
,其中 XXXX 是4位數(shù)的十六進(jìn)制值。例如,心型字符(♥)的編碼為\u2665
。要指定大于或小于4位十六進(jìn)制數(shù)字,請(qǐng)將值放在花括號(hào)中。例如笑臉表情(??)的編碼\u{1f600}
。
String 類有幾個(gè)屬性可以用來獲取 runes信息。codeUnitAt 和 codeUnit 屬性返回16位代碼單元。使用字符屬性獲取字符串的字符。
下面的示例說明了字符、16位代碼單元和32位代碼點(diǎn)之間的關(guān)系:
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)); } //運(yùn)行效果如下 ?? [55357, 56832] [128512] ? ?? ?? ?? ?? ?? Process finished with exit code 0
注意: 使用列表操作操作 runes 時(shí)要小心。根據(jù)特定的語言、字符集和操作,這種方法很容易出錯(cuò)。有關(guān)更多信息,請(qǐng)參見如何在Dart中反轉(zhuǎn)字符串?
2.2.8 Symbols(符號(hào))
符號(hào)對(duì)象表示在 dart 程序中聲明的操作符或標(biāo)識(shí)符。一般來說可能永遠(yuǎn)不需要使用符號(hào),但是對(duì)于按名稱引用標(biāo)識(shí)符的api 來說,它們是非常重要的,因?yàn)榭s小改變了標(biāo)識(shí)符名稱而不是標(biāo)識(shí)符符號(hào)。
要獲取標(biāo)識(shí)符的符號(hào),請(qǐng)使用符號(hào)文字,符號(hào)文字僅為#
,后面跟著標(biāo)識(shí)符:
#radix #bar
注意: 符號(hào)常量是編譯時(shí)常量。
2.2.9 枚舉類型
枚舉類型可以看做是 dart 對(duì)類(class)的一種延伸。
使用enum
關(guān)鍵字聲明一個(gè)枚舉類型:
enum Color { red, green, blue }
枚舉中的每個(gè)值都有一個(gè)索引 getter,它返回enum
聲明中值的從0開始的位置。例如,第一個(gè)值有索引0,第二個(gè)值有索引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
的所有值,將會(huì)報(bào)一個(gè)警告消息:
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' }
枚舉類型有以下限制:
- 不能子類化、混合或?qū)崿F(xiàn)枚舉。
- 不能顯式實(shí)例化一個(gè)枚舉。
以上就是Dart語法之變量聲明與數(shù)據(jù)類型實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于Dart變量聲明數(shù)據(jù)類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Flutter學(xué)習(xí)筆記(三)RowColum布局
這篇文章主要介紹了Flutter學(xué)習(xí)筆記(三)RowColum布局,通俗來說,就是橫向布局和縱向布局的用法,需要的朋友可以參考下2023-04-04Flutter SizedBox布局組件Widget使用示例詳解
這篇文章主要為大家介紹了Flutter SizedBox布局組件Widget使用示例詳解2023-02-02Android開發(fā)中Dart語言7個(gè)很酷的特點(diǎn)
這篇文章主要為大家介紹了Android開發(fā)中Dart語言7個(gè)很酷的特點(diǎn)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Flutter 語法進(jìn)階抽象類和接口本質(zhì)區(qū)別詳解
這篇文章主要為大家介紹了Flutter 語法進(jìn)階抽象類和接口本質(zhì)區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08一文詳解Dart如何實(shí)現(xiàn)多任務(wù)并行
這篇文章主要為大家介紹了Dart如何實(shí)現(xiàn)多任務(wù)并行示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03