##轉載請註明出處: learnandfish.com/
入門簡單的Dart程式
// 定義一個函式
printNumber(int number) {
print('The number is $number.'); // 列印到控制檯。
}
// 入口函式
void main() {
var number = 42; // 宣告並初始化一個變數。
printNumber(number); // 呼叫函式。
}
複製程式碼
- // 程式碼註釋。
- $variableName (或 ${expression}) 獲取變數值
重要概念
在學習 Dart 語言時, 應該基於以下事實和概念:
- 萬物皆物件, 無論是數字,函式和null都是物件。所有物件繼承自Object類。
- 儘管Dart語言是強型別的, 但是Dart可以推斷型別, 上面的var number等價於int number。
- 針對於不確定的資料型別,請使用dynamic。
- Dart支援泛型, 如List(整數列表)和List(任何型別的物件列表)。
- 與Java不同, Dart中沒有許可權關鍵字"public", "protected", "private"。 如果識別符號以下劃線(_number)開頭, 則認為是私有屬性。
- Dart語言定義的變數,如果不賦值,預設為空null。
變數
Dart內建資料型別如下:
- Number 通過num宣告
- int 整數值
- double 雙精度浮點值
void main() {
var number = 1; // Dart會自動推斷為int型別
int value = 1; // 顯示宣告為int型別
print(number == value); // 該值應為true, 因為上述兩個變數的值和型別相同
var pointNumber = 1.0; // Dart會自動推斷為double型別
double pointValue = 1.0; // 顯示宣告為double型別
double pointValueCast = 1; // Dart2.1之後會自動轉換為為double型別
print(pointNumber == pointValue); // 該值應為true, 因為上述兩個變數的值和型別相同
print(pointNumber == pointValueCast); // 該值應為true, 因為上述兩個變數的值和型別相同
}
複製程式碼
- String
- 以單引號或者雙引號包裹。
- 可以通過"+"連線。
- 可以通過$variableName或者${expression}獲取取值。
- 使用r字首建立原始字串。
- 物件的常用方法請查閱String常用方法
void main() {
var s1 = "我是字串1";
String s2 = "我是字串2";
// s3雖然手動換行,但是輸出的時候還是在一行
var s3 = '我是'
'字串'
'3';
// s4和s5為多行字串
var s4 = """
我是
字串
4
哈哈哈
""";
var s5 = '''
我是
字串
4
哈哈哈
''';
// s6會換行
var s6 = "In a raw string, even \n isn't special.";
// s7保持原樣輸出
var s7 = r"In a raw string, even \n isn't special.";
print(s1);
print(s2);
print(s3);
print(s4);
print(s5);
print(s6);
print(s7);
}
/* console
我是字串1
我是字串2
我是字串3
我是
字串
4
哈哈哈
我是
字串
4
哈哈哈
In a raw string, even
isn't special.
In a raw string, even \n isn't special.
*/
複製程式碼
- Boolean
- Dart 使用 bool 型別表示布林值。 Dart 只有字面量 true and false 是布林型別, 這兩個物件都是編譯時常量。
void main() {
var b = true;
var c = false;
bool d; // 宣告變數不賦值的情況下,預設為null
bool e = true;
print(b);
print(c);
print(d);
print(e);
}
/* console
true
false
null
true
*/
複製程式碼
- List
- 幾乎每種程式語言中最常見的集合可能是array或有序的物件集合。在Dart中的Array就是List物件, 通常稱之為List。
void main() {
var list = [1, 2, 3];
List list1 = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
}
複製程式碼
- Set
- 在Dart中Set是一個元素唯一且無序的集合。
void main() {
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
// Dart 推斷 halogens 型別為 Set<String> 。如果嘗試為它新增一個 錯誤型別的值,分析器或執行時會丟擲錯誤。
halogens.add('haha'); // 新增成功
// halogens.add(1); // 型別錯誤,編譯時提示
// 要建立一個空集,使用前面帶有型別引數的 {} ,或者將 {} 賦值給 Set 型別的變數
var names = <String>{};
Set<String> names1 = {}; // 這樣也是可以的。
// var names = {}; // 這樣會建立一個 Map ,而不是 Set 。
var elements = <String>{};
// 使用 add() 或 addAll() 為已有的 Set 新增元素
elements.add('fluorine');
elements.addAll(halogens);
// 使用 .length 來獲取 Set 中元素的個數
assert(elements.length == 5);
}
複製程式碼
- Map
- Map是用來關聯keys和values的物件。keys和values可以是任何型別的物件。
- 在一個Map物件中一個key只能出現一次。但是value可以出現多次。
void main() {
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
// 以上 Map 物件也可以使用 Map 建構函式建立
var gifts1 = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases2 = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
// 賦值
gifts['fourth'] = 'calling birds';
// 從一個 Map 中獲取一個 value
var first = gifts['first'];
// 獲取Map的長度
print(gifts.length);
}
複製程式碼
- Rune和Symbol
- 不常用,有興趣可以自行學習。
- 通過Symbol宣告的變數, 通過#variableName呼叫
final和const
- 使用過程中從來不會被修改的變數, 可以使用final或const, 而不是var或者其他型別。
- final變數的值只能被設定一次; const變數在編譯時就已經固定(const變數是隱式final型別)。
void main() {
final name = 'Bob';
final String nickname = 'Bobby';
// name = 'Jack'; // Error: 一個 final 變數只能被設定一次。
// const是編譯時就固定值
const bar = 1000000; // 壓力單位 (dynes/cm2)
const double atm = 1.01325 * bar; // 標準氣壓
// Const 關鍵字不僅可以用於宣告常量變數。 還可以用來建立常量值。
var foo = const []; // 等價於 var foo = [];
final bar1 = const [];
const baz = []; // Equivalent to `const []`
// 非 Final , 非 const 的變數是可以被修改的,即使這些變數 曾經引用過 const 值。
foo = [1, 2, 3]; // 曾經引用過 const [] 常量值。
// final和const修飾的不能修改
// bar1 = [1]; // 編譯時報錯, final修飾的不可修改
// baz = [2]; // 編譯時報錯, const修飾的不可修改
}
複製程式碼
函式
- Dart 是一門真正物件導向的語言, 甚至其中的函式也是物件, 並且有它的型別Function。
- 這也意味著函式可以被賦值給變數或者作為引數傳遞給其他函式。也可以把Dart類的例項當做方法來呼叫。
// 有返回值的函式
bool showPrice() {
return true;
}
// 返回值為void
void printVoidNumber() {
print('return void');
}
// 返回值為void, 此時void的可以省略
printVoidNumber1() {
print('return void');
}
// 如果一個函式函式體只有一行,可以用箭頭代替大括號
// => expr 語法是 { return expr; } 的簡寫。 => 符號 有時也被稱為 箭頭 語法。
showBooleanValue() => true;
// 將函式賦值給一個變數
var a = showBooleanValue();
void main() {
print(a);
}
複製程式碼
- 可選引數
- 命名可選引數, 放在大括號內{}
void enableFlags({bool bold, bool hidden}) {}
複製程式碼
- 位置可選引數, 放在中括號內[]
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
// 方法呼叫
void main() {
say('Bob', 'Howdy'); //不使用可選引數
say('Bob', 'Howdy', 'smoke signal'); //使用可選引數
}
複製程式碼
- 預設引數值
/// 設定 [bold] 和 [hidden] 標誌 ...
void enableFlags({bool bold = false, bool hidden = false}) {}
void main(){
// bold 值為 true; hidden 值為 false.
enableFlags(bold: true);
}
複製程式碼
- 函式是一等公民
- 一個函式可以作為另一個函式的引數。
- 同樣可以將一個函式賦值給一個變數。
printElement(int element) => print(element);
void mian(){
var list = [1, 2, 3];
// 將 printElement 函式作為引數傳遞。
list.forEach(printElement);
}
複製程式碼
- 匿名函式
void main() {
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
}
複製程式碼
- 閉包:其實閉包就是在一個函式中可以呼叫其他的函式,這樣其他的函式可以使用本函式的引數及其他內容。
運算子
- 型別判斷運算子
- as 型別轉換
- is 判斷是否為某型別
- is! 判斷不是某型別
- 賦值運算子
- a = value; 將value賦值給便里昂a
- b ??= value; 如果b為空時, 將value賦值給b, 否則b的值保持不變。
- 條件表示式
- condition ? expr1 : expr2 如果條件為 true, 執行 expr1 (並返回它的值): 否則, 執行並返回 expr2 的值。
- expr1 ?? expr2 如果 expr1 是 non-null, 返回 expr1 的值; 否則, 執行並返回 expr2 的值。
- 級聯運算子
- 可以實現對同一個物件進行一系列的操作。
- 除了呼叫函式, 還可以訪問同一物件上的欄位屬性。這通常可以節省建立臨時變數的步驟, 同時編寫出更流暢的程式碼。
- 類似與build模式。
class Person{
int age;
String name;
Person({this.name, this.age});
void say(String words) {
print(name + words);
}
}
void main(){
Person() // 獲取物件。
..name = 'Bob' // 呼叫成員變數。
..say('important');
// 等價於下面的程式碼
var person = Person(name: "Bob");
person.say('important');
// 級聯運算子可以巢狀
/*final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();*/
// 在返回值為void的函式之後不能繼續呼叫級聯操作符
var sb = StringBuffer();
sb.write('foo') // write函式返回值是void, 不能再繼續呼叫
..write('bar'); // 執行會報錯
}
複製程式碼
控制流程語句
// if elseif else
weatherStatus(){
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
}
// for 迴圈
text(){
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('---$i!');
}
// for ... in ...
var collection = [0, 1, 2];
for (var x in collection) {
print(x); // 0 1 2
}
// forEach
collection.forEach((item) => print(item));
}
// while 和 do-while
printSomethings() {
while (!isDone()) {
doSomething();
}
do {
printLine();
} while (!atEndOfPage());
}
// break 和 continue
pauseSomethings(){
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
// 執行yearsExperience大於等於5的元素
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
// 如果candidate物件實現了Iterable介面, 可以呼叫如下方式
candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
}
// switch 和 case
judgeType() {
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED': // 當command為該種情況時,由於該分支沒有break語句會繼續執行下一個分支,直到遇到break停止執行。
executeDenied();
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
}
// assert 判斷是否成立
judgeEquals() {
// 確認變數值不為空。
assert(text != null);
// 確認變數值小於100。
assert(number < 100);
// 確認 URL 是否是 https 型別。
assert(urlString.startsWith('https'));
// assert 的第二個引數可以為其新增一個字串訊息。
assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".');
}
複製程式碼
異常處理
- Dart 程式碼可以丟擲和捕獲異常。
- 異常表示一些未知的錯誤情況。如果異常沒有被捕獲, 則異常會丟擲, 導致丟擲異常的程式碼終止執行。
- throw 可以丟擲Dart定義的異常, 也可以丟擲任意物件
// 高質量的生產環境程式碼通常會實現 Error 或 Exception 型別的異常丟擲。
throw FormatException('Expected at least 1 section');
throw 'Out of llamas!';
// 完整的try catch finally程式碼
try {
// 程式碼塊
} on Exception catch (e) {
// 捕獲到異常走這裡
} finally {
// 無論是否捕獲異常, 最終都會走這裡
}
複製程式碼
類和建構函式
- 通過class關鍵字宣告。
- 在沒有宣告建構函式的情況下, Dart會提供一個預設的建構函式。預設建構函式沒有引數並會呼叫父類的無參建構函式。
class Point {
num x, y;
// 建構函式的第一種方法
Point(num x, num y) {
// 還有更好的方式來實現下面程式碼,敬請關注。
this.x = x;
this.y = y;
}
// 建構函式的第二種方法
Point(this.x, this.y)
// 建構函式的第三種方法--命名建構函式
Point.origin(){
x = 0;
y = 0;
}
}
複製程式碼
- 類的繼承
- 子類通過關鍵字extends繼承父類。
- 預設情況下, 子類的建構函式會自動呼叫父類的預設建構函式(匿名, 無引數)。
- 如果父類沒有匿名無參的建構函式, 則在子類中需要手動呼叫父類的建構函式。
class Person {
String firstName;
Person.fromJson(Map data){
print("I'm $firstName");
}
}
class Employee extends Person {
Employee.fromJson(Map data) : super.fromJson(data){
print("I'm Employee");
}
}
main() {
var emp = new Employee.fromJson({});
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
}
複製程式碼
- 建構函式不僅可以呼叫父類建構函式, 還可以在建構函式體執行之前初始化成員變數。
import 'dart:math';
class Point {
final num x;
final num y;
final num distance;
Point(x, y)
: x = x,
y = y,
distance = sqrt(x * x + y * y);
}
複製程式碼
- 重定向建構函式
class Point {
num x, y;
// 類的主建構函式。
Point(this.x, this.y);
// 指向主建構函式
Point.alongXAxis(num x) : this(x, 0);
}
複製程式碼
- 常量建構函式
- 如果該類生成的物件是固定不變的, 那麼就可以把這些物件定義為編譯時常量。
- 為此需要定義一個const建構函式, 並且宣告所有例項變數為final。
class ImmutablePoint {
static final ImmutablePoint instance =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
複製程式碼
- 工廠建構函式
- 當執行建構函式並不總是建立這個類的一個新例項時, 則使用 factory 關鍵字。
- 一個工廠建構函式可能返回一個cache中的例項。
class Logger {
final String name;
bool mute = false;
// 從命名的 _ 可以知,
// _cache 是私有屬性。
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
// 私有命名建構函式
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
複製程式碼
- Getter 和 Setter方法
class Person {
num age;
final String name;
final String hobby;
// Getter
String get hobby => "basketball";
// Setter
set hobby(String hobbyName) => hobby = hobbyName;
Person(this.name, this.age)
}
複製程式碼
- abstract 和 implements
- abstract抽象類, 類中的抽象方法通過分號結束, 不用實現函式體, 故可以省略大括號。
- implements實現介面。每個類都隱式的定義了一個介面, 介面包含該類所有的成員及其實現的介面。
// 抽象類
abstract class Person {
void walk(); // 抽象方法
}
class Animal {
void fly() => print("I can fly");
}
class Bird implements Animal {
void fly() {
// 具體實現
}
}
複製程式碼
- 重寫運算子 通過operator重寫
class Vector {
final int x, y;
Vector(this.x, this.y);
// 返回值 operator 運算子(引數) {具體實現}
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
}
複製程式碼
- noSuchMethod()
- 當程式碼嘗試呼叫類中不存在的方法時, 會丟擲NoSuchMethodError異常, 可以通過重寫該方法實現自己想要的結果。
class Animal {
@override
void noSuchMethod(Invocation invocation){
// 具體實現
}
}
複製程式碼
- 列舉型別
enum Color {
RED, GREEN, BLUE
}
複製程式碼
- Mixin為類新增新功能
- Mixin是複用類程式碼的一種途徑, 複用的類可以不存在繼承關係。
- 通過with後面跟一個或者多個類進行復用。
- 通過mixin定義一個Mixin類, Mixin類通過on複用其他類
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
mixin MusicalPerformer on Musician {}
複製程式碼
- 靜態變數和靜態型別
class Animal {
static const height = 180;
static num distance(){
return 100;
}
}
複製程式碼
庫
// 通過import匯入
import 'dart:html';
// 通過as指定別名, 呼叫時通過lib2呼叫
import 'package:lib2/lib2.dart' as lib2;
// 匯入庫的一部分, 減少包體積
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
// 延遲載入庫, 當使用時進行載入
import 'package:greetings/hello.dart' deferred as hello;
Future greet() async {
// 使用時使用loadLibrary()載入
await hello.loadLibrary();
hello.printGreeting();
}
複製程式碼
非同步(Future和Stream)
- Future 使用async 和 await 構造。
Future<bool> downLoad(String url) async {
val result = await down();
return result;
}
複製程式碼
typedefs
- 為函式定義別名
typedefs Compare<T> = int Function(T a, T b);
複製程式碼
註釋
// 單行註釋
/*
多行註釋
多行註釋
多行註釋
*/
/// 文件註釋
/// 文件註釋
/**
* 文件註釋
*/
複製程式碼
如果你覺得本篇部落格對你有用,可以點個贊,評個論或者打個賞給博主增加動力哦。