這一篇我們不講Flutter 的知識,來講一講Dart 的基礎知識。
先來看看維基百科上關於Dart 的簡介:
Dart(是一種適用於全球資訊網的開放原始碼程式語言,由Google主導開發,於2011年10月公開。它的開發團隊由Google Chrome瀏覽器V8引擎團隊的領導者拉爾斯·巴克主持,目標在於成為下一代結構化Web開發語言。
類似JavaScript,Dart也是一種物件導向語言,但是它採用基於類程式設計。它只允許單一繼承,語法風格接近C語言。
再開啟 Dart 官網:dart.dev,映入眼簾的是:
emmmm….很明顯,現在知道 Dart 語言的人大部分都是因為 Flutter,這與它的目標成為下一代結構化Web開發語言好像有點偏差。(不過在Flutter 1.5 釋出的時候釋出了 Flutter for web)
不過無所謂,無論它最開始的目標是什麼,既然我們現在想要學習 Flutter ,那就要了解 Dart 這門開發語言。
話不多說,我們開始。
首先我們要知道,Dart是一個純面嚮物件語言,也就是說,在Dart中,一切皆物件。
Dart程式碼長什麼樣子
好像我們看到的 Dart 程式碼都是從 Flutter 裡看見的,一個括號套一個括號,一大堆的括號。
那麼標準的 Dart 程式碼是什麼樣的:
// 定義個方法。
printNumber(num aNumber) {
print('The number is $aNumber.'); // 在控制檯列印內容。
}
// 這是程式執行的入口。
main() {
var number = 42; // 定義並初始化一個變數。
printNumber(number); // 呼叫一個方法。
}
複製程式碼
好像沒什麼不同的,只是有一個 num 好像有點不太一樣(因為我是搞Android的,所以上來就看到了這一個問題)。
那我們就從變數開始講起。
變數
宣告變數
在 Dart 中,我們宣告一個變數有兩種方法:
var _str = '';
int _num = 1;
複製程式碼
所有用下劃線開頭的 無論是方法 還是變數 都是私有的。
我們可以用var 來宣告一個變數,也可以指定變數的型別。
那麼我們什麼時候用什麼樣的方式來宣告變數呢?
可以通過Dart程式碼風格推薦裡來查詢到:
對於區域性變數,使用 var
而不是具體的型別來定義區域性變數。
對於私有成員變數,推薦使用指定變數的型別來宣告變數。
常量
在 Dart 中,我們宣告常量有兩種方法:
const String constString = "";
final String _finalString;
複製程式碼
一種是用 const,一種是用 final。
兩種有什麼區別?
const
const 是在編譯時期就必須賦值,而且 const 在類中的話,就必須定義為 static const.
final
final 講道理不能說是定義為常量,而應該叫做不能被修改的變數。
因為被 final 修飾的變數只能在類初始化時賦值一次。在編譯時我們看不到其值。
所有內建的變數型別
Dart 內建支援下面這些型別:
- numbers
- strings
- booleans
- lists (也被稱之為 arrays)
- maps
- runes (用於在字串中表示 Unicode 字元)
- symbols
簡單說兩個
numbers
Dart 支援兩種數值型別 int double ,這兩種型別都是 num 的子類
也就是說只要你定義的是數值型別,就可以用 num 來接收。
strings
String 可以用雙引號或者單引號來宣告。
在字串中可以用表示式 ${}
,也可以用 + 號來拼接字串。
其他的就不說了,至於後兩個很大可能用不到。
方法
Dart 是一個真正的面嚮物件語言,方法也是物件並且具有一種型別, Function
型別。
也就是說,我們可以把方法賦值成變數,來傳入另一個方法。
一個簡單的方法
來定義一個簡單的方法:
Widget build(BuildContext context) {
return Container();
}
複製程式碼
就拿 Flutter 中的 build來說,這就是一個最基本的 Dart 方法。
返回型別為 Widget, 形參為 BuildContext。裡面只有一行程式碼 return Container();
那對於一個方法中只有一個表示式的,我們可以這麼寫:
Widget build(BuildContext context) => Container();
複製程式碼
這個 => Container();
語法是 { return Container; }
形式的縮寫。=>
語法也稱為 胖箭頭 語法。
可選引數
方法可以有兩種型別的引數:必需的和可選的。 必需的引數在引數列表前面, 後面是可選引數。
在 Dart 中可選引數也有兩種,可選命名引數 和 可選位置引數
可選命名引數
String demo(String name, {int age}){
String result = '我的名字叫$name';
if(age != null){
result += ',我今年$age歲了';
}
return result;
}
複製程式碼
這就是一個可選的命名引數,我們這樣呼叫:
demo('HaSaKi', age: 18);
複製程式碼
可選位置引數
我們把剛才的demo 方法改造一下:
String demo(String name, [int age]){
String result = '我的名字叫$name';
if(age != null){
result += ',我今年$age歲了';
}
return result;
}
複製程式碼
把大括號改為了中括號,這樣就成為了可選位置引數的方法。
要這樣呼叫:
demo('HaSaKi', 18);
複製程式碼
引數預設值
在定義方法的時候,我們可以使用 = 來定義引數的預設值
預設值必須是編譯時常量。
舉個例子:
String demo(String name, {int age = 18}){
String result = '我的名字叫$name';
if(age != null){
result += ',我今年$age歲了';
}
return result;
}
複製程式碼
這個方法現在就算不傳 age 的值,也永遠都會輸出,我今年18歲了。因為給了age預設值。
類
Dart 中的類和Java 類似,單繼承,並且 Object 是所有類的超類。
定義一個類:
class Person{
String name;
int age;
say(){
assert(name == null);
print('我叫$name');
}
}
複製程式碼
可以說和其他語言一樣了。
下面來點不一樣的。
簡化變數賦值
在其他語言中,我們經常會使用建構函式來給類變數賦值。
由於這種需求特別常見,所以 Dart 提供了一個語法糖:
class Person {
String name;
int age;
Person(this.name, this.age);
say() {
assert(name == null);
print('我叫$name');
}
}
複製程式碼
命名建構函式
在 Dart 中,可以使用命名建構函式來更清晰的表達你的意圖:
class Person {
String name;
int age;
Person.fromJson(Map json) {
this.name = json['name'];
this.age = json['age'];
}
say() {
assert(name == null);
print('我叫$name');
}
}
複製程式碼
工廠構造方法
如果一個建構函式並不總是返回一個新的物件,則使用 factory
來定義這個建構函式。
單例也是我們經常使用的, 我們可以使用工廠構造方法來讓我們實現單例:
class Person {
static final Person _person = Person._internal();
factory Person() {
return _person;
}
Person._internal();
}
複製程式碼
可以看到,我們定義了一個私有命名建構函式,也定義了一個工廠建構函式。
定義一個 final 的 Person 物件,然後用工廠建構函式返回它。
我們來測試一下:
print(Person() == Person());
flutter: true
複製程式碼
可以證明這樣寫是沒問題的。
級聯呼叫
我們平時為類的值賦值或呼叫方法的時候,是這麼寫的:
var person = Person();
person.name = '哈哈';
person.age = 18;
person.say();
複製程式碼
有沒有很麻煩?Dart 也為我們考慮到了:
Person()
..name = '哈哈'
..age = 18
..say();
複製程式碼
總結
目前就寫這麼多基礎的知識吧,可以看到 Dart 為我們開發人員考慮了很多,是個現代化語言該有的樣子。
而現在我們在Flutter 當中所看到的 Dart 程式碼只是冰山一角,後續我也會繼續為大家寫Dart 系列。
請持續關注。