Dart 是谷歌于2011年10月10日發(fā)布一門開源編程語言(日子挑的不錯)。2018年之前一直處于蟄伏狀態(tài),flutter 之后聲名雀起,一發(fā)不可收拾!
Dart 的存在的存在的意義是什么呢?看一下官網(wǎng)的概述:
Dart is a client-optimized language for developing fast apps on any platform. Its goal is to offer the most productive programming language for multi-platform development, paired with a flexible execution runtime platform for app frameworks.
廢話說完了,進入正題!
Hello Dart
怎么能少得了 Hello World !
// 程序入口函數(shù)
void main() {
// 函數(shù)調(diào)用
printHelloWorld();
}
// 定義函數(shù) printHelloWorld
void printHelloWorld() {
// 實現(xiàn),打印 Hello World
print("Hello World !");
}
如上,一個簡單的 Hello World 就寫完了。可以自己打開 DartPad 進行練手!
Dart 語法學習的過程中均可在其上進行練習,灰常方便!
Dart 語言特點
Dart 語言具有以下特點:
0、編譯型;
1、強類型(Dart 2 才是);
2、面向?qū)ο螅磺薪詫ο螅瑪?shù)字、函數(shù)、null 都是對象;
語法
變量
使用關(guān)鍵字 var
進行變量的聲明。
// 聲明一個字符串變量 name 并賦值 Yuri
var name = "Yuri";
// 聲明一個變量 temperature 并賦值 35.0
var temperature = 35.0;
由于 Dart 有類型推斷機制,name 會被自動判斷為 String
類型。
也可以使用類型顯式的聲明一個變量:
String name = "Yuri";
double temperature = 28.5;
還可以使用 dynamic
或 Object
聲明一個變量。但 dynamic
和 Object
的變量可以在后期改變賦值的類型,而 Var 聲明的變量則不可以。 dynamic
這個特性與 Objective-C 中的 id
作用很像. dynamic 的這個特點使得我們在使用它時格外需要注意,因為很容易引入運行時錯誤。
dynamic name = "Yuri";
Object temperature = 28.5;
print("$name, $temperature");
// 打印結(jié)果:Yuri, 28.5
name = 28.5;
temperature = "Yuri";
print("$name, $temperature");
// 打印結(jié)果:28.5, Yuri
常量
使用關(guān)鍵字 final
或 const
聲明一個常量。
// 使用 final 聲明一個 sex 的常量
final sex = "male";
// 使用 const 聲明一個 nickName 的常量
const nickName = "Kitty";
使用 final
和 Const
聲明的常量的值不能被修改。
final
和 const
的區(qū)別在哪呢?
const
定義的常量在編譯時就已經(jīng)固定,final
定義的常量則在第一次使用時才被初始化。
Dart 內(nèi)建類型
Number
Number 有兩種類型 int
和 double
。
// 定義一個 int 類型變量
int x = 1;
// 定義一個 double 類型變量
double y = 3.14;
int
整數(shù)值不大于64位, 具體取決于平臺。 在 Dart VM 上, 值的范圍從 -263 到 263 - 1. Dart 被編譯為 JavaScript 時,使用 JavaScript numbers, 值的范圍從 -253 到 253 - 1.
double
: 64位(雙精度)浮點數(shù),依據(jù) IEEE 754 標準。
String
Dart 字符串是一組 UTF-16 單元序列。字符串通過單引號或雙引號創(chuàng)建。
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}
的方式內(nèi)嵌表達式。 如果表達式是一個標識符,則{}
可以省略。
var s = 'string interpolation';
print("Dart has $s, which is very handy.");
在 Dart 中通過調(diào)用就對象的 toString()
方法來得到對象相應的字符串。
String oneAsString = 1.toString();
assert(oneAsString == '1');
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
可以使用 +
運算符來把多個字符串連接為一個,也可以把多個字面量字符串寫在一起來實現(xiàn)字符串連接。
var s1 = 'String '
'concatenation'
" works even over line breaks.";
print(s1);
// 打印結(jié)果: String concatenation works even over line breaks.
var s2 = 'The + operator ' + 'works, as well.';
print(s2);
// 打印結(jié)果:The + operator works, as well.
Boolean
bool
,表示布爾值,有 true
和 false
兩個值。
bool isSunny = true;
bool isRainy = false;
List (也被稱為 Array)
List 表示有序集合。
// 定義一個 整形 的數(shù)組字面量
var list = [1, 2, 3];
// 獲取數(shù)組長度
var length = list.length;
// 訪問數(shù)組元素. List 元素的下標也是從 0 開始的
var secondValue = list[1];
Map
通常來說, Map
是用來關(guān)聯(lián) keys 和 values 的對象。
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
也可以使用 Map 的構(gòu)造函數(shù)創(chuàng)建對象。
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
向 Map 添加一個 key-value
gifts["sixth"] = "cake";
訪問 Map 中的 value
var sixthGift = gifts["sixth"];
assert(sixthGift == "cake");
Set
Set 表示無序元素的集合,集合內(nèi)元素唯一。
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
創(chuàng)建一個空集
var names = <String>{};
向 set 中添加元素
names.add("1");
names.addAll({"2", "3"});
Rune (用于在字符串中表示 Unicode 字符)
Dart 字符串是一系列 UTF-16 編碼單元,即每個字符占 16 位, 而 Unicode 則是 32 位的,因此 Dart 字符串中表示 32 位 Unicode 值需要特殊語法支持。
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(new String.fromCharCodes(input));
Symbol
一個 Symbol 對象表示 Dart 程序中聲明的運算符或者標識符。 你也許永遠都不需要使用 Symbol ,但要按名稱引用標識符的 API 時, Symbol 就非常有用了。 因為代碼壓縮后會改變標識符的名稱,但不會改變標識符的符號。 通過字面量 Symbol ,也就是標識符前面添加一個 # 號,來獲取標識符的 Symbol 。
#radix
#bar
Symbol 字面量是編譯時常量。
函數(shù)
Dart 中一切皆對象。函數(shù)也是對象,其對應的類型為 Function
。
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
在 Effective Dart 中推薦 公共API中聲明類型, 但是省略了類型聲明,函數(shù)依舊是可以正常使用的
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
如果函數(shù)中只有一句表達式,可以使用簡寫語法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=> expr
語法是 { return expr; }
的簡寫。 =>
符號 有時也被稱為 箭頭 語法。
在 Dart 語言中,函數(shù)是一等對象(難道還有二等,三等?)。
函數(shù)可以作為另一個函數(shù)的參數(shù),同時也可以把函數(shù)賦值給一個變量。
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 將 printElement 函數(shù)作為參數(shù)傳遞。
list.forEach(printElement);
// 將函數(shù)作為值賦給變量
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
匿名函數(shù)
一般情況下函數(shù)是有名字的,把沒有名字的函數(shù)叫做匿名函數(shù)。
匿名函數(shù)有時也被稱為 lambda 或者 closure。
在將函數(shù)作為值賦值給變量時,我們用的就是一個匿名函數(shù)。
可選參數(shù)
可選參數(shù)分命名參數(shù)和位置參數(shù)。一個參數(shù)只能選擇其中一種進行修飾。
命名可選參數(shù)
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {
...
}
調(diào)用
enableFlags(bold: true, hidden: false);
命名可選參數(shù)可以用 @required 進行修飾,表示在函數(shù)調(diào)用時該參數(shù)不可缺少。
const Scrollbar({Key key, @required Widget child})
此時 Scrollbar 是一個構(gòu)造函數(shù), 當 child 參數(shù)缺少時,分析器會提示錯誤。
位置可選參數(shù)
將參數(shù)放到 []
中來標記參數(shù)是可選的
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
默認參數(shù)
在定義函數(shù)時,我們可以給參數(shù)一個默認值。
/// 設(shè)置 [bold] 和 [hidden] 標志 ...
void enableFlags({bool bold = false, bool hidden = false}) {
...
}
// bold 值為 true; hidden 值為 false.
enableFlags(bold: true);
運算符
算術(shù)運算符
操作符 | 功能 |
---|---|
+ | 加 |
- | 減 |
* | 乘 |
/ | 除 |
~/ | 除法取整 |
% | 模(余數(shù)) |
除了上面的基本的算術(shù)運算符,Dart 同樣也支持帶有前綴的自增和自減運算符。
++expr
, expr++
,--expr
,expr--
/// 基本操作運算符示例
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 結(jié)果是雙浮點型
assert(5 ~/ 2 == 2); // 結(jié)果是整型
assert(5 % 2 == 1); // 余數(shù)
/// 自增自減運算符示例
var a, b;
a = 0;
b = ++a; // a自加后賦值給b。
assert(a == b); // 1 == 1
a = 0;
b = a++; // a先賦值給b后,a自加。
assert(a != b); // 1 != 0
a = 0;
b = --a; // a自減后賦值給b。
assert(a == b); // -1 == -1
a = 0;
b = a--; // a先賦值給b后,a自減。
assert(a != b); // -1 != 0
關(guān)系運算符
操作符 | 功能 |
---|---|
== | 等于 |
!= | 不等于 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
比較簡單,不再示例。
類型判定運算符
操作符 | 功能 |
---|---|
as | 類型轉(zhuǎn)化 |
is | 類型判斷(True if the object has the specified type) |
is! | 類型判斷(False if the object has the specified type) |
is
比較好理解,是就返回 true,不是就返回 false;
而 is!
意義則相反,不是就返回 true,是就返回 false;
個人感覺大部分情況下,is
就夠了!
賦值運算符
=
是基本的賦值運算符,通過與其它操作符的組合,會產(chǎn)生許多其它的復合賦值運算符。如下
= | -= | /= | %= | >>= | ^= |
---|---|---|---|---|---|
+= | *= | ~/= | <<= | &= | |= |
比較簡單,不再示例。
邏輯運算符
操作符 | 含義 |
---|---|
&& | 與 |
|| | 或 |
! | 非 |
不再示例。
按位和移位運算符
操作符 | 含義 |
---|---|
& | 按位與(AND) |
| | 按位或(OR) |
^ | 按位異或(XOR) |
~expr | 取反(Unary bitwise complement (0s become 1s; 1s become 0s)) |
<< | 左移(Shift left) |
>> | 右移(Shift right) |
條件表達式
condition ? expr1 : expr2
如果條件為 true, 執(zhí)行 expr1 (并返回它的值): 否則, 執(zhí)行并返回 expr2 的值。
var visibility = isPublic ? 'public' : 'private';
expr1 ?? expr2
如果 expr1 是 non-null, 返回 expr1 的值; 否則, 執(zhí)行并返回 expr2 的值。
String playerName(String name) => name ?? 'Guest';
級聯(lián)運算符
級聯(lián)運算符 ..
可以實現(xiàn)對同一個對像進行一系列的操作。除了調(diào)用函數(shù), 還可以訪問同一對象上的字段屬性。
querySelector('#confirm') // 獲取對象。
..text = 'Confirm' // 調(diào)用成員變量。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
這個運算符在 iOS 開發(fā)過程中沒有遇到過,應該是 Dart 特胡的語法糖。
其它運算符
Operator | Name | Meaning |
---|---|---|
() | Function application | Represents a function call |
[] | List access | Refers to the value at the specified index in the list |
. | Member access | Refers to a property of an expression; example: foo.bar selects property bar from expression foo |
?. | Conditional member access | Like ., but the leftmost operand can be null; example: foo?.bar selects property bar from expression foo unless foo is null (in which case the value of foo?.bar is null) |
控制流程語句
if ... else ...
注意:條件語句必須是布爾值
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
for loops
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
while and do-while loops
while (!isDone()) {
doSomething();
}
do {
printLine();
} while (!atEndOfPage());
break and continue
break: 停止程序循環(huán)。
continue:跳過當次循環(huán)。
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
switch and case
注意:正常情況下,case 中的 break 不可省略。
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
assert
如果 assert 語句中的布爾條件為 false , 那么正常的程序執(zhí)行流程會被中斷。
// 確認變量值不為空。
assert(text != null);
// 確認變量值小于100。
assert(number < 100);
// 確認 URL 是否是 https 類型。
assert(urlString.startsWith('https'));
異常處理
Dart 可以拋出和捕獲異常。
throw
throw 用于拋出異常。
當函數(shù)執(zhí)行過程中出現(xiàn)了異常,可以通過 throw 將異常拋出。異常可以是 Exception 或 Error,或其它任何非 null 對象。當拋出異常時,程序也將會被終止。
throw FormatException('Expected at least 1 section');
以下示例拋出了一條字符串消息
throw 'Out of llamas!';
catch
捕獲異常可以避免異常繼續(xù)傳遞.
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}
通過指定多個 catch 語句,可以處理可能拋出多種類型異常的代碼。 與拋出異常類型匹配的第一個 catch 語句處理異常。 如果 catch 語句未指定類型, 則該語句可以處理任何類型的拋出對象:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 一個特殊的異常
buyMoreLlamas();
} on Exception catch (e) {
// 其他任何異常
print('Unknown exception: $e');
} catch (e) {
// 沒有指定的類型,處理所有異常
print('Something really unknown: $e');
}
如上述代碼所示,捕獲語句中可以同時使用 on
和 catch
,也可以單獨分開使用。 使用 on
來指定異常類型, 使用 catch
來 捕獲異常對象。
catch()
函數(shù)可以指定1到2個參數(shù), 第一個參數(shù)為拋出的異常對象, 第二個為堆棧信息 ( 一個 StackTrace 對象 )。
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
如果僅需要部分處理異常, 那么可以使用關(guān)鍵字 rethrow 將異常重新拋出。
void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
finally
不管是否拋出異常, finally 中的代碼都會被執(zhí)行。 如果 catch 沒有匹配到異常, 異常會在 finally 執(zhí)行完成后,再次被拋出:
try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
任何匹配的 catch 執(zhí)行完成后,再執(zhí)行 finally :
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}