前些日子在公司嘗試着使用 Flutter 開發一些功能。要想寫好 Flutter 程序,首先 Dart 語言是基礎。前端
固然,在實際開發中,可能因爲時間的關係,不用瞭解到 Dart 的方方面面纔開始 Flutter 的開發,能夠邊學邊用。python
爲了造成一個完整的體系,我想先系統的講解下 Dart 語言,而後在開始 Flutter 相關的介紹。git
Dart 相對於 Java 來講有更強的變現力,甚至我以爲比 Kotlin 還要有表現力。Dart 不只能夠用來開發客戶端,還能夠用來開發Web前端和後端開發。github
因此呢,我以爲 Dart 仍是一門值得學習的語言,下面就開始咱們的 Dart 學習之旅吧web
本文是 Dart 相關的第一篇,主要介紹 Dart 語言的變量的定義和類型體系正則表達式
按照慣例,學習一門語言都是從 Hello World 開始的。下面咱們看下 Dart 的 Hello World 程序:express
main(){
var str = "Hello world!";
print(str);
}
複製代碼
上面咱們提到了 Dart 是支持類型推導的,因此在定義變量的時候能夠經過 var 關鍵字來定義編程
固然也能夠顯示的指定 變量的類型,如:後端
// 經過 var 關鍵字定義變量,省略具體的類型
var str = "Hello world!";
// 顯式指定變量類型
String str = "Hello World!"
複製代碼
在 Dart 中萬物皆對象,如 null、函數、數字 都是對象數組
因此咱們的定義的變量若是沒有給初始值,那麼這個變量的默認是就是 null
int lineCount;
assert(lineCount == null);
複製代碼
定義變量的時候,可使用 final 關鍵字來修飾,如
final String name = "chiclaim";
name = "johnny"; // Error
複製代碼
final定義的變量,在定義的時候就要初始化,而且只能賦值一次
定義變量的時候還可使用 const 關鍵字來修飾:
const name = "chiclaim"
name = "johnny"; // Error
複製代碼
const 關鍵字修飾變量,說明這個變量是 編譯時常量,如數字、字符串字面量都是 編譯時常量
const 和 final 區別是 final 表示這個變量只能被賦值一次,const 表示該變量不只只能被賦值一次,而且該變量是一個常量
const 不只能夠修飾變量,還能夠修飾變量的值,表示該值不能修改:
main(){
// 經過 const 關鍵字修飾foo變量的值
var foo = const [];
// 因爲 foo 的值被 const 修飾,因此不能修改裏面的值
// 運行時錯誤,Unsupported operation: Cannot modify an unmodifiable list
foo[0] = 0;
// 能夠賦值,由於 foo 變量沒有被 final 或 const 修飾
foo = [1,2,3];
// 因爲foo變量被從新賦值,因此能夠修改裏面的值
foo[0] = 0;
print(foo);
}
複製代碼
Dart 類型系統以下所示:
不像 C/C++/Java 等語言,在 Dart 表示數字的類型只有兩個:int 和 double
int :表示沒有小數點的整型,最大值不大於64-bit(-2^63 ~ 2^63-1)底層依賴的系統最大值也不一樣,若是編譯後用於JavaScript,則最大值爲 -2^53 ~ 2^53-1
double 表示雙精度的浮點型
int age = 17;
double weight = 65.5;
double waistline = 30; // 至關於 30.0
複製代碼
字符串和數字類型之間互轉:
// 字符串轉化成整型
int num = int.parse("2");
// 字符串轉化成浮點型
double pi = double.parse("3.14");
// 浮點型轉成字符串
String piStr = 3.14.toString();
// 浮點型轉成用小數表示的字符串(能夠選擇保留幾位小數)
String piAsStringFix = 3.14159.toStringAsFixed(2);
複製代碼
一個 Dart 字符串是個 UTF-16 碼元(code units)序列,可使用單引號或雙引號來建立一個字符串
// 雙引號建立一個字符串字面量
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."; 複製代碼
建立原生(raw)字符串,在字符串前面加上前綴 r:
// 通常 \n 是換行符,若是咱們想把 \n 當作字符串輸出時候,也可使用建立原生字符串的方式
var raw = r'In a raw string, not even \n gets special treatment.';
複製代碼
咱們還能夠將表達式(${expression})嵌入字符串中:
const name = "chiclaim";
// 將表達式${expression}嵌入字符串中
var info = "My name is ${name}";
// 若是表達式是一個標識符,能夠省略花括號
var info2 = "My name is $name";
複製代碼
字符串的拼接:
// 1. 經過 + 號來拼接字符串
var s2 = 'The + operator ' + 'works, as well.';
// 2. 毗鄰的字符串字面量
var s1 = 'String '
'concatenation'
" works even over line breaks.";
// 3. 經過多行字符串(使用三引號)
var s1 = ''' You can create multi-line strings like this one. ''';
var s2 = """This is also a multi-line string.""";
複製代碼
// Check whether a string contains another string.
assert('Never odd or even'.contains('odd'));
// Does a string start with another string?
assert('Never odd or even'.startsWith('Never'));
// Does a string end with another string?
assert('Never odd or even'.endsWith('even'));
// Find the location of a string inside a string.
assert('Never odd or even'.indexOf('odd') == 6);
複製代碼
// 字符串截取
assert('Never odd or even'.substring(6, 9) == 'odd');
// 使用正則表達式分割字符串,返回字符串集合
var parts = 'structured web apps'.split(' ');
// 經過索引獲取字符串的UTF-16編碼單元
assert('Never odd or even'[0] == 'N');
// 循環打印字符串中的字符串
for (var char in 'hello'.split('')) {
print(char);
}
// 獲取字符串中的全部UTF-16碼元
var codeUnitList ='Never odd or even'.codeUnits.toList();
// N 的 ASCII 編碼的十進制就是 78
assert(codeUnitList[0] == 78);
複製代碼
// 轉成大寫
assert('structured web apps'.toUpperCase() == 'STRUCTURED WEB APPS');
// 轉成小寫
assert('STRUCTURED WEB APPS'.toLowerCase() == 'structured web apps');
複製代碼
// 去除頭尾的空格
print(' hello '.trim() == 'hello');
// 字符串是否爲空
print(''.isEmpty);
// 空格不是空字符串
print(' '.isNotEmpty);
// 空格trim後,就變成空字符串
print(' '.trim().isNotEmpty);
複製代碼
字符串是不可變的,替換函數不是修改原字符串,而是會產生一個新的字符串
var greetingTemplate = 'Hello, NAME!';
var greeting = greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');
// greetingTemplate didn't change. assert(greeting != greetingTemplate); 複製代碼
經過編程的方式生成一個字符串,可使用 StringBuffer 來實現,直到調用 StringBuffer.toString() 函數纔會建立字符串
var sb = StringBuffer();
// 經過 .. 實現鏈式調用
sb
..write('Use a StringBuffer for ')
// 寫入一個字符串列表,以空格分割
..writeAll(['efficient', 'string', 'creation'], ' ')
..write('.');
// 建立字符串
var fullString = sb.toString();
assert(fullString ==
'Use a StringBuffer for efficient string creation.');
複製代碼
在 Dart 中經過 bool 關鍵字來描述布爾,布爾有兩個值:true和false。 true 和 false 都是編譯器常量
bool isSuccess = true;
bool isFailed = false;
複製代碼
List不只用來表示List集合(有序的數據集合),也用來表示數組
下面來看下如何建立一個List 字面量
var list = [1, 2, 3]; // 類型推導出list是 List<int>
複製代碼
介紹 const 關鍵字的時候,也用 const 修飾 List 的值 如:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // Error.
複製代碼
Dart2.3 提供了展開操做符(... 和 ...?) 讓開發者更加方便的將多個值插入到集合中
var list = [1, 2, 3];
// 展開操做符(...) spread operator
var list2 = [0, ...list];
var list;
// 展開操做符(...?) null-aware spread operator
var list2 = [0, ...?list];
複製代碼
Dart2.3 除了提供了展開操做符,還有 collection if 和 collection for
// collection if
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
// collection for
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
複製代碼
collection if/for 在開發Flutter的時候頗有用,能夠簡化不少代碼
Set 表示一個無序的集合,下面看下如何建立一個 Set 字面量
// halogens is Set<String>
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
複製代碼
建立一個空 Set :
// 經過var和泛型推導出Set類型
var names = <String>{};
// 顯式指定是Set類型
Set<String> names = {};
須要注意的是下面是建立了一個Map
var names = {};
複製代碼
相似地,展開操做符 和 collection if/for 也能夠用到 Set 中
Map 是一個 鍵值對 集合,下面來看下如何建立 Map 字面量:
// gifts is Map<String, String>
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
// nobleGases is Map<int, String>
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
複製代碼
須要注意的時候,Key只能出現一次,不然會被後面的替換掉
經過中括號 [] 來添加、修改、獲取Map中的元素:
var gifts = Map();
// 添加元素
gifts['first'] = 'partridge';
var gifts = {'first': 'partridge'};
// 獲取經過Key獲取Map中的元素
assert(gifts['first'] == 'partridge');
var gifts = {'first': 'partridge'};
// 修改Map中的元素
gifts['fourth'] = 'calling birds';
複製代碼
相似地,展開操做符 和 collection if/for 也能夠用到 Set 中
關於 Dart 的 展開操做符 以及 collection if/for 更多內容能夠查看:
(二)Flutter學習之Dart展開操做符 和 Control Flow Collections
在 Dart 中,Rune類型是一個字符串的UTF-32的碼點(code points),咱們在介紹 String 類型的時候,提到了 code units
那麼在介紹 Rune 以前,咱們先來看下 code points 和 code units 是什麼?
Unicode 編碼爲世界上全部的字母、數字、符號定義了對應的數字來表示
由於 Dart 字符串是 UTF-16 碼元的序列,描述 32-bit Unitcode 的字符串須要特殊的語法
一般地, Unicode使用 \uXXXX 描述碼點 ,這裏的 XXXX 是一個4位十六進制的值,例如描述心形的符號使用 \u2665 表示
若是多於或者少於 4 個十六進制,則須要加上花括號,例如笑的表情使用 \u{1f600}
String 類有幾個屬性能夠提取字符串的 rune 信息 (例如屬性 runes),codeUnitAt 和 codeUnit 屬性返回 16 bit的 碼元(code units)
main() {
var clapping = '\u{1f44f}';
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));
}
複製代碼
在 Dart 全部的類都是繼承自 Object,和Java相似。dynamic 和 Object 容許全部的值賦值給它:
dynamic name;
Object email;
main() {
name = "chiclaim";
email = "chiclaim@gmail.com";
}
複製代碼
可是他們是兩個徹底不一樣的概念。你甚至能夠把 dynamic 不要當作一個類型看待,dynamic 顧名思義就是動態的意思,它只是告訴編譯器不要作類型檢查
dynamic name;
Object email;
main() {
// 將 String 賦值給 name
name = "chiclaim";
// 打印 name 的長度
print(name.length);
// 將 int 賦值給name
name = 1;
// 編譯器並不會報錯(編譯時不作類型檢查),運行時纔會報錯
// NoSuchMethodError: Class 'int' has no instance getter 'length'.
print(name.length);
email = "chiclaim@gmail.com";
// 編譯器報錯,由於 Object 沒有 length 屬性
print(email.length);
}
複製代碼
經過上面的代碼示例,相信你對 dynamic 和 Object 的區別有了比較清楚的理解
Dart 在官網的最佳實踐中建議開發者,若是你想表達意思是任何對象均可以,使用 Object 代替 dynamic
若是你容許類型推導失敗,通常推到失敗,編譯器會默認給dynamic,可是建議顯式地寫上 dynamic ,由於代碼的閱讀者不知道你是忘記了寫類型仍是:
// 建議
dynamic mergeJson(dynamic original, dynamic changes){
}
// 不建議
mergeJson(original, changes){
}
複製代碼
關於 Dart 變量和類型系統 就講到這裏, 更多的關於 Android
學習資料能夠查看個人GitHub: github.com/chiclaim/An…
dart.dev/guides/lang… github.com/acmerfight/…
下面是個人公衆號,乾貨文章不錯過,有須要的能夠關注下,有任何問題能夠聯繫我: