Dart 語言了解
概念
當您了解Dart語言時,請記住以下事實和概念:
-
您可以放在變量中的所有內容都是一個對象,每個對象都是一個類的實例。偶數,函數和 null對象。所有對象都從Object類繼承。
-
盡管Dart是強類型的,但類型注釋是可選的,因為Dart可以推斷類型。在上面的代碼中,number 推斷為類型int。如果要明確說明不需要任何類型,請 使用特殊類型dynamic。
-
Dart支持泛型類型,如
List<int>
(整數列表)或List<dynamic>
(任何類型的對象列表)。 -
Dart支持頂級函數(例如main()),以及綁定到類或對象的函數(分別是靜態和實例方法)。您還可以在函數內創建函數(嵌套函數或本地函數)。
-
類似地,Dart支持頂級變量,以及綁定到類或對象的變量(靜態和實例變量)。實例變量有時稱為字段或屬性。
-
與Java,飛鏢不具備關鍵字public,protected和private。如果標識符以下划線(_)開頭,則它對其庫是私有的。有關詳細信息,請參閱 庫和可見性。
-
標識符可以以字母或下划線(_)開頭,后跟這些字符加數字的任意組合。
-
Dart有兩個表達式(具有運行時值)和 語句(不具有)。例如,條件表達式 condition ? expr1 : expr2的值為expr1或expr2。將其與if-else語句進行比較,該語句沒有任何值。語句通常包含一個或多個表達式,但表達式不能直接包含語句。
-
Dart工具可以報告兩種問題:警告和錯誤。警告只是表明您的代碼可能無法正常工作,但它們不會阻止您的程序執行。錯誤可以是編譯時或運行時。編譯時錯誤會阻止代碼執行; 運行時錯誤導致 代碼執行時引發異常。
變量
這是創建變量並初始化它的示例:
var name = 'Bob';
變量存儲引用。調用的變量name包含對String值為“Bob” 的對象的引用。
name推斷變量的類型String,但您可以通過指定它來更改該類型。如果對象不限於單一類型,請按照設計指南指定Object或dynamic類型。
dynamic name = 'Bob' ;
另一種選擇是顯式聲明可以推斷出的類型:
String name = 'Bob' ;
默認值
未初始化的變量的初始值為null。即使是帶有數字類型的變量最初也是null,因為數字也都是對象。
int lineCount ; assert (lineCount == null );
最終和常數
如果您從不打算更改變量,請使用final或const代替var或替代類型。最終變量只能設置一次; const變量是編譯時常量。
以下是創建和設置最終變量的示例:
final name = 'Bob' ; //沒有類型注釋
final String nickname = 'Bobby' ;
使用const為您要為變量的編譯時間常數。如果const變量在類級別,請標記它static const。在聲明變量的地方,將值設置為編譯時常量,例如數字或字符串文字,const變量或常數上的算術運算結果:
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere
內置類型
- numbers 數字
- strings 字符串
- booleans 布爾
- lists 列表(也稱為數組)
- maps 映射
- runes 符文(用於表示字符串中的Unicode字符)
- symbols 符號
數字
兩種形式:
int
整數值不大於64位,具體取決於平台。
double
64位(雙精度)浮點數,由IEEE 754標准規定。
字符串
Dart字符串是一系列UTF-16代碼單元。您可以使用單引號或雙引號來創建字符串:
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.";
布爾
類型bool。只有兩個對象具有bool類型:true和false,它們都是編譯時常量。
// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);
// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);
// Check for null.
var unicorn;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
Lists
也許幾乎每種編程語言中最常見的集合是數組或有序的對象組。在Dart中,數組是 List對象,因此大多數人只是將它們稱為列表。
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
Maps
通常,映射是關聯鍵和值的對象。鍵和值都可以是任何類型的對象。每個鍵只出現一次,但您可以多次使用相同的值。
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
Runes
在Dart中,符文是字符串的UTF-32代碼點。
Unicode為世界上所有書寫系統中使用的每個字母,數字和符號定義唯一的數值。由於Dart字符串是一系列UTF-16代碼單元,因此在字符串中表示32位Unicode值需要特殊語法。
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));
}
Symbols
符號對象表示達特程序聲明的操作者或標識符。您可能永遠不需要使用符號,但它們對於按名稱引用標識符的API非常有用,因為縮小會更改標識符名稱而不會更改標識符符號。
要獲取標識符的符號,請使用符號文字, #后面跟着標識符:
#radix
#bar
符號文字是編譯時常量。
功能
Dart是一種真正的面向對象語言,因此即使是函數也是對象並且具有類型Function。 這意味着函數可以分配給變量或作為參數傳遞給其他函數。您也可以像調用函數一樣調用Dart類的實例。
以下是實現函數的示例:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
main()函數
每個應用程序都必須具有頂級main()功能,該功能用作應用程序的入口點。該main()函數返回void並具有List
以下main()是Web應用程序的功能示例:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
注意:..前面代碼中 的語法稱為級聯。使用級聯,您可以對單個對象的成員執行多個操作。
作為第一類對象的函數
您可以將函數作為參數傳遞給另一個函數。例如:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
控制流程語句
您可以使用以下任一方法控制Dart代碼的流程:
if 和 else
for 循環
while 和 do-while 循環
break 和 continue
switch 和 case
assert
也可以使用 try-catch 和影響控制流 throw,如異常中所述。
示例
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
while (!isDone()) {
doSomething();
}
do {
printLine();
} while (!atEndOfPage());
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();
}
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}
類
Dart是一種面向對象的語言,具有類和基於mixin的繼承。每個對象都是一個類的實例,所有類都來自Object。 基於Mixin的繼承意味着雖然每個類(除了Object)只有一個超類,但是類體可以在多個類層次結構中重用。
class Point {
num x; // Declare instance variable x, initially null.
num y; // Declare y, initially null.
num z = 0; // Declare z, initially 0.
Point(num x, num y) {
// There's a better way to do this, stay tuned.
this.x = x;
this.y = y;
}
num distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
class Rectangle {
num left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
}
抽象類和方法
抽象方法
實例,getter和setter方法可以是抽象的,定義一個接口,但將其實現留給其他類。抽象方法只能存在於抽象類中。
抽象類
使用abstract修飾符定義抽象類 - 無法實例化的類。抽象類對於定義接口非常有用,通常還有一些實現。如果希望抽象類看起來是可實例化的,請定義工廠構造函數。
abstract class Doer {
// Define instance variables and methods...
void doSomething(); // Define an abstract method.
}
class EffectiveDoer extends Doer {
void doSomething() {
// Provide an implementation, so the method is not abstract here...
}
}
繼承和實現
實現:
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}
// An implementation of the Person interface.
class Impostor implements Person {
get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
}
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
繼承:
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
重寫:
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}
枚舉類型
枚舉類型(通常稱為枚舉或枚舉)是一種特殊類,用於表示固定數量的常量值。
使用枚舉
使用enum關鍵字聲明枚舉類型:
enum Color { red, green, blue }
靜態類變量和方法
使用static關鍵字實現類范圍的變量和方法。
靜態變量:
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
靜態方法:
import 'dart:math';
class Point {
num x, y;
Point(this.x, this.y);
static num distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}
泛型
如果您查看基本數組類型的API文檔 List,您會看到該類型實際上是List
var names = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
使用庫
使用import指定如何從一個庫中的命名空間在另一個庫的范圍內使用。
唯一需要的參數import是指定庫的URI。對於內置庫,URI具有特殊dart:方案。對於其他庫,您可以使用文件系統路徑或package: 方案。該package:方案指定由包管理器(如pub工具)提供的庫。
import 'dart:html';
import 'package:test/test.dart';
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
異步支持
Dart庫中包含許多返回Future或Stream對象的函數。這些函數是異步的:它們在設置可能耗時的操作(例如I/O)后返回,而不等待該操作完成。
處理Future
當您需要完成的Future的結果時,您有兩個選擇:
- 使用async和await。
- 使用Future API。
使用async和await異步的代碼,但它看起來很像同步代碼。
await lookUpVersion();
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
使用try,catch和finally 處理使用await以下代碼的錯誤和清理:
try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}
聲明異步函數
一個異步函數是一個函數體標有async修改。
將async關鍵字添加到函數使其返回Future。
Future<String> lookUpVersion() async => '1.0.0';
如果您的函數沒有返回有用的值,請設置其返回類型Future<void>
。
處理Streams
當您需要從Stream獲取值時,您有兩個選擇:
- 使用async和異步for循環(await for)。
- 使用Stream API。
注意: 在使用之前await for,請確保它使代碼更清晰,並且您確實希望等待所有流的結果。
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}
Generators
當您需要延遲地生成一系列值時,請考慮使用生成器函數。Dart內置支持兩種形式:
- 同步生成器:返回一個Iterable對象。
- 異步生成器:返回Stream對象。
要實現同步生成器函數,請將函數體標記為sync,並使用yield語句來傳遞值。
要實現異步生成器函數,請將函數體標記為async,並使用yield語句來傳遞值。
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}