前言
Flutter應用程序使用Dart語言開發(fā),Dart是面向?qū)ο缶幊陶Z言,由Google于2011年推出,目前最新版本是2.0,為了更好的使用Flutter進行應用開發(fā),本文將詳細介紹Dart語言的語法和特性。
一、重要概念
在學習Dart之前,先要了解以下Dart相關概念:
能夠放在變量中的所有內(nèi)容都是對象,每個對象都是一個類的實例。甚至于數(shù)字、函數(shù)和null值都是對象,并且所有對象都繼承自Object類。
Dart是強類型語言,但類型標識是可選的,因為Dart可以推斷類型。如果要明確說明不需要任何類型,可以使用特殊類型dynamic標識。
Dart支持泛型,如List或List(任何類型的對象列表)。
Dart支持頂級函數(shù)(例如main函數(shù)),以及綁定到類或?qū)ο蟮暮瘮?shù)(分別是靜態(tài)方法和實例方法)。函數(shù)內(nèi)部也可以創(chuàng)建函數(shù)(嵌套函數(shù)或本地函數(shù))。
Dart支持頂級變量,以及綁定到類或?qū)ο蟮淖兞浚ǚ謩e是靜態(tài)變量和實例變量)。
與Java不同,Dart沒有關鍵字public、protected和private。如想設置私有變量或函數(shù),則變量和函數(shù)名以下劃線()開頭。
標識符可以以字母或下劃線()開頭,后跟這些字符加數(shù)字的任意組合。
Dart有兩個表達式(具有運行時值)和語句(不具有)。 例如,條件表達式條件? expr1:expr2的值為expr1或expr2。 將其與if-else語句進行比較,該語句沒有任何值。 語句通常包含一個或多個表達式,但表達式不能直接包含語句。
Dart工具可以報告兩種問題:警告和錯誤。警告只是表明您的代碼可能無法正常工作,但它們不會阻止您的程序執(zhí)行。 錯誤可以是編譯時或運行時。 編譯時錯誤會阻止代碼執(zhí)行; 運行時錯誤導致代碼執(zhí)行時引發(fā)異常。
二、關鍵字
任何語言都有關鍵字,關鍵字是在編程時不能使用作為標識符的單詞。Dart的關鍵字如下:
編碼時應避免使用以上單詞作為標識符,如果有必要,可以使用帶有上標的單詞作為標識符:
帶有上標1的單詞是上下文關鍵字,僅在特定位置有含義,它們在任何地方都是有效的;
帶有上標2的單詞是內(nèi)置標識符,它們在大多數(shù)地方是有效的,但不能用作為類和類型名稱或作為一個導入前綴;
帶有上標3的單詞是與Dart1.0發(fā)布后添加的異步支持相關的有限的保留字符,不能在任何標記為async,async * 或sync * 的任何函數(shù)體中使用await和yield作為標識符。
三、變量
變量的定義
1.可以使用var來定義變量,變量的類型可以通過變量值推斷出來
var name = "hi"; //String類型
var age = 18; //int類型
var high = 1.70; //double類型
如上變量定義后其類型已經(jīng)確定,不可再將其他類型的值賦給變量。
var name = "hi"; //String類型
name = 3; //此處編譯器會報錯,name被定義賦值之后已經(jīng)是一個String類型,不可再賦值int類型值
2.也可以使用特定類型來定義變量
String name = "bruce"; //String類型
int age = 18; //int類型
3.如果變量不限于單個類型,則可以使用dynamic或Object來定義變量
dynamic value = 18;
print("value = value");
value = 3.5;
print("value = $value");
Object val = 18;
print("val = val");
val = 3.5;
print("val = $val");
輸出結果為
value = 18
value = bruce
value = 3.5
val = 18
val = bruce
val = 3.5
變量的默認值
由于前文關于Dart的一些概念中說到過,能夠放在變量中的所有內(nèi)容都是對象,所以如果一個變量沒有初始化值,那它的默認值就為null。
int value1;
print("value1 = value2");
var value3;
print("value3 = value4");
輸出結果為
value1 = null
value2 = null
value3 = null
value4 = null
final 和 const
如果不打算更改變量,可以使用final或者const。一個final變量只能被設置一次,而const變量是編譯時常量,定義時必須賦值。
// Person類
class Person {
static const desc = "This is a Person class"; //必須定義時賦值,否則編譯時報錯
final name;
Person(this.name); //對象初始化時賦值一次
}
// 定義一個Person對象
Person p = Person("Bruce"); //創(chuàng)建對象時設置一次name
print("p.name = ${p.name}"); //可正常輸出 p.name = Bruce
p.name = "haha"; //編譯器報錯
四、內(nèi)置類型
Dart語言支持以下類型
numbers : 包含int和double兩種類型,沒有像Java中的float類型,int和double都是num的子類型。
strings : Dart的字符串是一系列UTF-16代碼單元。創(chuàng)建方法如下:
String str1 = "hello"; //可以使用單引號或雙引號
print("str1 = str2");
輸出結果為
str1 = hello
str2 = Hi,Bruce
This is Xiaoming.
booleans : Dart有一個名為bool的類型,只有兩個對象具有bool類型:true和false,他們都是編譯時常量。
lists : 和其他編程語言常見的集合一樣,Dart中使用的集合是數(shù)組或有序的對象組。Dart中數(shù)組是List對象。
List arr = ["Bruce", "Nick", "John"];
print("arr = $arr");
maps
Map map = {
"name": "Bruce",
"age": 18,
"high": 1.70
};
print("map = {map['name']}");
var map1 = {
1: "hi",
2: "hello",
3: "yep"
};
print("map1 = {map1[1]}");
輸出結果為
map = {name: Bruce, age: 18, high: 1.7}
map['name'] = Bruce
map1 = {1: hi, 2: hello, 3: yep}
map1[1] = hi
runes
符文是字符串的UTF-32代碼點。在字符串中表示32位Unicode值需要特殊語法,常用方法是 \uXXXX,其中XXXX是4位十六進制值,比如小心心(?)是\u2665。要指定多于或少于4個十六進制數(shù)字,請將值放在大括號中。 比如,微笑(??)是\u{1f600}。
String smile = '\u{1f600}';
print("微笑:$smile");
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(String.fromCharCodes(input));
輸出結果為
微笑:??
? ?? ?? ?? ?? ??
五、函數(shù)
Dart是一種真正的面向?qū)ο笳Z言,因此即使是函數(shù)也是對象并且具有類型Function。這意味著函數(shù)可以分配給變量或作為參數(shù)傳遞給其他函數(shù)。
定義方法
和絕大多數(shù)編程語言一樣,Dart函數(shù)通常的定義方式為
String getName() {
return "Bruce";
}
如果函數(shù)體中只包含一個表達式,則可以使用簡寫語法
String getName() => "Bruce";
可選參數(shù)
Dart函數(shù)可以設置可選參數(shù),可以使用命名參數(shù)也可以使用位置參數(shù)。
命名參數(shù),定義格式如 {param1, param2, …}
// 函數(shù)定義
void showDesc({var name, var age}) {
if(name != null) {
print("name = age");
}
}
// 函數(shù)調(diào)用
showDesc(name: "Bruce");
// 輸出結果
name = Bruce
位置參數(shù),使用 [] 來標記可選參數(shù)。
// 函數(shù)定義
void showDesc(var name, [var age]) {
print("name = $name");
if(age != null) {
print("age = $age");
}
}
// 函數(shù)調(diào)用
showDesc("Bruce");
// 輸出結果
name = Bruce
默認值
函數(shù)的可選參數(shù)也可以使用 = 設置默認值
// 函數(shù)定義
void showDesc(var name, [var age = 18]) {
print("name = $name");
if(age != null) {
print("age = $age");
}
}
// 函數(shù)調(diào)用
showDesc("Bruce");
// 輸出結果
name = Bruce
age = 18
main函數(shù)
和其他編程語言一樣,Dart中每個應用程序都必須有一個頂級main()函數(shù),該函數(shù)作為應用程序的入口點。
函數(shù)作為參數(shù)
Dart中的函數(shù)可以作為另一個函數(shù)的參數(shù)。
// 函數(shù)定義
void println(String name) {
print("name = $name");
}
void showDesc(var name, Function log) {
log(name);
}
// 函數(shù)調(diào)用
showDesc("Bruce", println);
// 輸出結果
name = Bruce
匿名函數(shù)
// 函數(shù)定義
void showDesc(var name, Function log) {
log(name);
}
// 函數(shù)調(diào)用,匿名函數(shù)作為參數(shù)
showDesc("Bruce", (name) {
print("name = $name");
});
// 輸出結果
name = Bruce
嵌套函數(shù)
Dart支持嵌套函數(shù),也就是函數(shù)中可以定義函數(shù)。
// 函數(shù)定義
void showDesc(var name) {
print("That is a nested function!");
//函數(shù)中定義函數(shù)
void println(var name) {
print("name = $name");
}
println(name);
}
// 函數(shù)調(diào)用
showDesc("Bruce");
// 輸出結果
That is a nested function!
name = Bruce
六、運算符
Dart中使用到的運算符如下表格
Description Operator
一元后綴 expr++ expr-- () [] . ?.
一元前綴 -expr !expr ~expr ++expr --expr
乘除操作 * / % ~/
加減操作 + -
移位 << >>
按位與 &
按位異或 ^
按位或 I
比較關系和類型判斷 >= > <= < as is is!
等判斷 == !=
邏輯與 &&
邏輯或 II
是否null ??
條件語句操作 expr1 ? expr2 : expr3
級聯(lián)操作 ..
分配賦值操作 = . *= . /= . ~/= . %= . += . -= . <<= . >>= . &= . ^= . I= . ??=
下面就對一些對于Java或Objective-C來說未使用過的運算符通過代碼來做個介紹。
?.的使用
//定義類
class Person {
var name;
Person(this.name);
}
// 調(diào)用
Person p;
var name = p?.name; //先判斷p是否為null,如果是,則name為null;如果否,則返回p.name值
print("name = $name");
// 輸出結果
name = null
~/的使用
// 代碼語句
var num = 10;
var result = num ~/ 3; //得出一個小于等于(num/3)的最大整數(shù)
print("result = $result");
// 輸出結果
result = 3
as的使用,as用來做類型轉(zhuǎn)化
// 類定義
class Banana {
var weight;
Banana(this.weight);
}
class Apple {
var weight;
Apple(this.weight);
}
// 調(diào)用
dynamic b = Banana(20);
(b as Banana).weight = 20; // 正常執(zhí)行
print("b.weight = {(b as Apple).weight}");
//輸出結果
b.weight = 20
Uncaught exception:
CastError: Instance of 'Banana': type 'Banana' is not a subtype of type 'Apple'
is的使用
// 函數(shù)和類代碼定義
getFruit() => Banana(20); // 獲取一個水果對象
class Banana {
var weight;
Banana(this.weight);
}
class Apple {
var color;
Apple(this.color);
}
// 調(diào)用
var b = getFruit();
if(b is Apple) { //判斷對象是否為Apple類
print("The fruit is an apple");
} else if(b is Banana) { //判斷水果是否為Banana類
print("The fruit is a banana");
}
// 輸出結果
The fruit is a banana
??的使用
// 操作代碼塊
String name;
String nickName = name ?? "Nick"; //如果name不為null,則nickName值為name的值,否則值為Nick
print("nickName = $nickName");
name = "Bruce";
nickName = name ?? "Nick"; //如果name不為null,則nickName值為name的值,否則值為Nick
print("nickName = $nickName");
// 輸出結果
nickName = Nick
nickName = Bruce
..的使用,級聯(lián)操作允許對同一個對象進行一系列操作。
// 類定義
class Banana {
var weight;
var color;
Banana(this.weight, this.color);
void showWeight() {
print("weight = $weight");
}
void showColor() {
print("color = $color");
}
}
// 調(diào)用
Banana(20, 'yellow')
..showWeight()
..showColor();
// 輸出結果
weight = 20
color = yellow
七、控制流語句
Dart中的控制流語句和其他語言一樣,包含以下方式
if and else
for循環(huán)
while和do-while循環(huán)
break和continue
switch-case語句
以上控制流語句和其他編程語言用法一樣,switch-case有一個特殊的用法如下,可以使用continue語句和標簽來執(zhí)行指定case語句。
var fruit = 'apple';
switch (fruit) {
case 'banana':
print("this is a banana");
continue anotherFruit;
anotherFruit:
case 'apple':
print("this is an apple");
break;
}
// 輸出結果
this is an apple
八、異常
Dart的異常捕獲也是使用try-catch語法,不過與java等語言稍有不同
// 定義一個拋出異常的函數(shù)
void handleOperator() => throw Exception("this operator exception!");
// 函數(shù)調(diào)用
try {
handleOperator();
} on Exception catch(e) {
print(e);
} finally { // finally語句可選
print("finally");
}
// 輸出結果
Exception: this operator exception!
finally
九、類
Dart是一種面向?qū)ο蟮恼Z言,具有類和基于mixin的繼承。同Java一樣,Dart的所有類也都繼承自Object。
構造函數(shù)
Dart的構造函數(shù)同普通函數(shù)一樣,可以定義無參和有參,命名參數(shù)和位置參數(shù),可選參數(shù)和給可選參數(shù)設置默認值等。Dart的構造函數(shù)有以下幾個特點:
可以定義命名構造函數(shù)
可以在函數(shù)體運行之前初始化實例變量
子類不從父類繼承構造函數(shù),定義沒有構造函數(shù)的子類只有無參無名稱的構造函數(shù)
子類定義構造函數(shù)時默認繼承父類無參構造函數(shù),也可繼承指定有參數(shù)的構造函數(shù);
命名構造函數(shù)和函數(shù)體運行前初始化實例變量
// 類定義
class Tree {
var desc;
// 命名構造函數(shù)
Tree.init() {
desc = "this is a seed";
}
// 函數(shù)體運行之前初始化實例變量
Tree(var des) : desc = des;
}
// 構造函數(shù)調(diào)用
Tree t = Tree.init();
print("${t.desc}");
Tree t1 = Tree("this is a tree");
print("${t1.desc}");
// 輸出結果
this is a seed
this is a tree
構造函數(shù)繼承
// 類定義
class Fruit {
Fruit() {
print("this is Fruit constructor with no param");
}
Fruit.desc(var desc) {
print("$desc in Fruit");
}
}
class Apple extends Fruit {
Apple():super() {
print("this is Apple constructor with no param");
}
// 默認繼承無參構造函數(shù)
Apple.desc(var desc) {
print('$desc in Apple');
}
}
// 構造函數(shù)調(diào)用
Apple();
Apple.desc("say hello");
// 輸出結果
this is Fruit constructor with no param
this is Apple constructor with no param
this is Fruit constructor with no param
say hello in Apple
mixin繼承
mixin是一種在多個類層次結構中重用類代碼的方法。
// 類定義
class LogUtil {
void log() {
print("this is a log");
}
}
class Fruit {
Fruit() {
print("this is Fruit constructor with no param");
}
}
class Apple extends Fruit with LogUtil {
Apple():super() {
print("this is Apple constructor with no param");
}
}
// 調(diào)用
Apple a = Apple();
a.log(); //可執(zhí)行從LogUtil繼承過來的方法
// 輸出結果
this is Fruit constructor with no param
this is Apple constructor with no param
this is a log
十、泛型
Dart同Java一樣,也支持泛型。
// 類定義
class Apple {
var desc;
Apple(this.desc);
void log() {
print("${this.desc}");
}
}
class Banana {
var desc;
Banana(this.desc);
void log() {
print("${this.desc}");
}
}
class FruitFactory<T> {
T produceFruit(T t) {
return t;
}
}
// 調(diào)用
FruitFactory<Banana> f = FruitFactory<Banana>();
Banana b = f.produceFruit(Banana("a banana"));
b.log();
FruitFactory<Apple> f1 = FruitFactory<Apple>();
Apple a = f1.produceFruit(Apple("an apple"));
a.log();
// 輸出結果
a banana
an apple
寫在最后
本文主要針對Dart不同于其他編程語言的一些語法特性進行了分析和舉例,相信讀過文本之后大家會對Dart語法有個很系統(tǒng)的了解,后邊我們就可以開啟Flutter應用開發(fā)之旅了。
來源:https://blog.csdn.net/weixin_43499085/article/details/88816331