Dart語言是使用flutter框架開發(fā)時(shí)候必備的語言吕喘,flutter是一個(gè)跨平臺(tái)的框架瓷胧,一套代碼就可以完美實(shí)現(xiàn)安卓和ios兩個(gè)平臺(tái)泪喊,適配也很不錯(cuò)窿克,Dart語言很友好,和java很類似毛甲,學(xué)習(xí)成本不高年叮,推薦學(xué)習(xí)。
接下來我會(huì)通過兩篇文章玻募,帶大家一起進(jìn)入Dart之旅只损。
目錄(誰知道簡(jiǎn)書md自動(dòng)生成目錄方法留言教我,謝謝)
概念
- 萬物皆對(duì)象七咧,所有的對(duì)象都是類的實(shí)例跃惫,如 數(shù)字、函數(shù)艾栋、null
等也都是對(duì)象爆存,所有的對(duì)象都繼承自 Object 類。 - 在 Dart 1.x 中蝗砾,強(qiáng)類型 strong mode 是可選的先较,但在 Dart 2 中,默認(rèn)就是 strong mode悼粮。
- Dart 支持頂級(jí)函數(shù)闲勺,也支持類或?qū)ο蟮撵o態(tài)和實(shí)例方法。也可以在函數(shù)內(nèi)部嵌套函數(shù)或本地函數(shù)扣猫;同樣支持頂級(jí)變量菜循,也支持類或?qū)ο蟮撵o態(tài)變量和實(shí)例變量(也被稱作字段或?qū)傩?
- Dart沒有 public、protected申尤、private等關(guān)鍵字癌幕,如果一個(gè)標(biāo)識(shí)符以 _開頭則表示私有
- 沒有初始化的變量都會(huì)被賦予默認(rèn)值null
類型:
numbers、strings瀑凝、bool序芦、list、map粤咪、runes谚中、symbol
numbers : 數(shù)據(jù)類型
- int 取值范圍:-2^53 to 2^53
- double
void _numbersDemo() {
int intNum = 12;
double doubleNum = 12.12;
//發(fā)現(xiàn) + 必須都是string類型的才可以,所以使用.toString()
print("int = " + intNum.toString() + " doubule=" + doubleNum.toString());
}
運(yùn)行結(jié)果:int = 12 doubule=12.12
strings : 字符串類型
- Dart 的String 是 UTF-16 編碼的一個(gè)隊(duì)列
- '...'寥枝、"..." 表示字符串
- '''...'''宪塔、"""..."""表示多行字符串
- r'...'、r"..."表示“raw”字符串
void _stringsDemo(){
String string1 = 'rocker1';
String string3 = '''rocker3_1
rocker3_2
rocker3_3''';
String string5Origin = 'rocker56 \nrocker56';
String string5 = r'rocker5 \n rocker5';
print(string1);
print(string3);
print("********");
print(string5Origin);
print(string5);
}
運(yùn)行結(jié)果:
rocker1
rocker3_1
rocker3_2
rocker3_3
********
rocker56
rocker56
rocker5 \n rocker5
bool : 布爾類型
與java類似囊拜,Dart 是強(qiáng) bool 類型檢查某筐,只有 bool 類型的值是true 才被認(rèn)為是 true
List : 列表、數(shù)組
具有一系列相同類型的數(shù)據(jù)被稱為 List 對(duì)象冠跷。
list 對(duì)象的第一個(gè)元素的位置是0南誊,最后個(gè)元素的索引是list.lenght - 1身诺。
void _listDemo(){
var names = new List();
//或者簡(jiǎn)單的用list來賦值
//List<String> names =["jim","rocker"]
//添加元素
names.add("rocker");
//添加多個(gè)元素
names.addAll(["jim","tom","abc","wangxiaojian"]);
//打印數(shù)組
print("before names="+names.toString());
//獲取list長(zhǎng)度
print("length="+names.length.toString());
//刪除指定元素,成功返回true,失敗返回false
names.remove("jim");
//刪除最后一個(gè)元素抄囚,返回刪除的元素 names.removeLast();
//刪除指定范圍元素霉赡,含頭不含尾,成功返回null names.removeRange(start,end);
// 刪除指定條件的元素幔托,成功返回null
names.removeWhere((item) => item.length >6);
//sort()對(duì)元素進(jìn)行排序穴亏,傳入一個(gè)函數(shù)作為參數(shù),return <0表示由小到大重挑, >0表示由大到小
names.sort((a, b) => a.compareTo(b));
print("after names="+names.toString());
}
運(yùn)行結(jié)果:
before names=[rocker, jim, tom, abc, wangxiaojian]
length=5
after names=[abc, rocker, tom]
map:字典
Map 類型將keys 和 values 關(guān)聯(lián)在一起嗓化。
keys 和 values 可以是任意類型的對(duì)象。
像其它支持Map 的編程語言一樣谬哀,Map 的 key 必須是唯一的刺覆。
void _mapDemo() {
// Map的聲明
var person = {
'wangxiaojian': ['15', "pingpang", 'other'],
'xiaoming': ['16', 'basketball'],
'aihua': ['15', 'football']
};
var person1 = new Map();
//指定鍵值對(duì)的參數(shù)類型
var dog = new Map<int, String>();
//Map的賦值,中括號(hào)中是Key玻粪,這里可不是數(shù)組
dog[54] = 'wangcai';
print("before dog[54]=" + dog[54] );
//Map中的鍵值對(duì)是唯一的,同Set不同隅津,第二次輸入的Key如果存在,Value會(huì)覆蓋之前的數(shù)據(jù)
dog[54] = 'tiedan';
print("after dog[54]=" + dog[54] );
//檢索Map是否含有某Key
print("does it include dog[54]=" + dog.containsKey(54).toString() );
//刪除某個(gè)鍵值對(duì)
dog.remove(54);
}
運(yùn)行結(jié)果:
before dog[54]=wangcai
after dog[54]=tiedan
does it include dog[54]=true
runes 類型
runes 是UTF-32字符集的string 對(duì)象劲室。
codeUnitAt 和 codeUnit 用來獲取UTF-16字符集的字符。
使用runes 來獲取UTF-32字符集的字符结窘。
void _testRunes(){
var string = '\u{1f44f}';
print(string);
print(string.codeUnits);
print(string.runes.toList());
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(input.toList());
}
運(yùn)行結(jié)果:
??
[55357, 56399]
[128079]
[9829, 32, 32, 128517, 32, 32, 128526, 32, 32, 128123, 32, 32, 128406, 32, 32, 128077]
Symbol
symbol字面量是編譯時(shí)常量很洋,在標(biāo)識(shí)符前面加#。如果是動(dòng)態(tài)確定隧枫,則使用Symbol構(gòu)造函數(shù)喉磁,通過new來實(shí)例化。
一般程序中不會(huì)使用Symbol類型官脓。
流程控制語句
- if...else
- for
- while do-whild
- break continue
- switch...case
- assert(僅在checked模式有效)
函數(shù)(Functions)
函數(shù)都有返回值协怒,如果沒有指定函數(shù)返回值,則默認(rèn)返回值是null卑笨,沒有返回值的函數(shù)孕暇,系統(tǒng)會(huì)在最后添加隱式的return 語句。
函數(shù)可以有兩種類型的參數(shù):
- 必須的:必須參數(shù)放在參數(shù)列表前面赤兴。
- 可選的:可選參數(shù)放在必須參數(shù)后面妖滔。
可選參數(shù)
可以通過名字或位置指定可選參數(shù),但是兩個(gè)不能同時(shí)存在桶良。
- 命名可選參數(shù)使用{}座舍,默認(rèn)值使用冒號(hào):,調(diào)用時(shí)需指明參數(shù)名陨帆,與順序無關(guān)曲秉。
void _testOptionParams(String name,{age:0,interest:null}){
print("name="+name+" age="+age.toString()+" interest="+interest.toString());
}
void main() {
_testOptionParams("wangxiaojian",age: 30,interest:"pingpang");
}
運(yùn)行結(jié)果:
name=wangxiaojian age=30 interest=pingpang
- 位置可選參數(shù)使用[]采蚀,默認(rèn)值使用等號(hào)=,調(diào)用時(shí)參數(shù)按順序賦值承二。
void _testOptionParams(String name,[age=0,interest=null]){
print("name="+name+" age="+age.toString()+" interest="+interest.toString());
}
void main() {
_testOptionParams("wangxiaojian","pingpang");
}
運(yùn)行結(jié)果:
name=wangxiaojian age=pingpang interest=null
操作符
is is搏存!操作符判斷對(duì)象是否為指定類型,如numbers矢洲、string等璧眠。
as用來類型斷言。
異常
throw
- 拋出固定類型的異常:
throw new FormatException('Expected at least 1 section');
- 拋出任意類型的異常:
throw 'Out of llamas!';
- 因?yàn)閽伋霎惓儆诒磉_(dá)式读虏,可以將throw語句放在=>語句中责静,或者其它可以出現(xiàn)表達(dá)式的地方:
distanceTo(Point other) =>
throw new UnimplementedError();
catch
將可能出現(xiàn)異常的代碼放置到try語句中,使用catch來處理異常。
可以向catch()傳遞1個(gè)或2個(gè)參數(shù)盖桥。第一個(gè)參數(shù)表示:捕獲的異常的具體信息灾螃,第二個(gè)參數(shù)表示:異常的堆棧跟蹤(stack trace)。
void _testException({demo:100}){
try{
var i = 2/0;
print(i.toString()+" "+demo);
}catch(e,s){
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
}
void main() {
_testException();
}
運(yùn)行結(jié)果:
Exception details:
type 'int' is not a subtype of type 'String'
Stack trace:
#0 _testException (file:///Users/wangxiaojian/Documents/androidCode/flutter_rong_app/test/widget_test.dart:99:28)
#1 main (file:///Users/wangxiaojian/Documents/androidCode/flutter_rong_app/test/widget_test.dart:13:3)
#2 _rootRun (dart:async/zone.dart:1126:13)
#3 _CustomZone.run (dart:async/zone.dart:1023:19)
#4 runZoned (dart:async/zone.dart:1501:17)
#5 Declarer.declare (package:test/src/backend/declarer.dart:121:22)
#6 RemoteListener.start.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test/src/runner/remote_listener.dart:118:26)
......
rethrow揩徊、finally
rethrow語句用來處理一個(gè)異常腰鬼,同時(shí)希望這個(gè)異常能夠被其它調(diào)用的部分使用。
finally用來執(zhí)行那些無論異常是否發(fā)生都執(zhí)行的操作塑荒。
void _testFinally({demo:100}) {
try {
print(" "+demo);
} catch (e) {
print('2');
rethrow;
}
}
void main() {
try {
_testFinally();
} catch (e) {
print('3');
} finally {
print('4'); // 即使沒有rethrow最終都會(huì)執(zhí)行到
}
}
運(yùn)行結(jié)果:
2
3
4
類
Dart 是一種面向?qū)ο蟮恼Z言熄赡,并且支持基于mixin的繼承方式:一個(gè)類可以繼承自多個(gè)父類。
使用new語句來構(gòu)造一個(gè)類齿税。構(gòu)造函數(shù)的名字可能是ClassName彼硫,也可以是ClassName.identifier。例如:
class Person{
var _name;
Person(){}
Person.initName(this._name);
}
void main() {
//使用new初始化對(duì)象
var person = new Person();
//使用ClassName.identifier初始化對(duì)象
var person1 = Person.initName("xiaojian");
}
- 使用.來調(diào)用實(shí)例的變量或者方法凌箕。
- 使用 ?. 來避免左邊操作數(shù)為null引發(fā)異常拧篮。
- 使用const替代new來創(chuàng)建編譯時(shí)的常量構(gòu)造函數(shù)。
- 兩個(gè)使用const構(gòu)建的同一個(gè)構(gòu)造函數(shù)牵舱,實(shí)例相等串绩。
- 獲取對(duì)象的運(yùn)行時(shí)類型使用:o.runtimeType。
實(shí)例化變量
在類定義中芜壁,所有沒有初始化的變量都會(huì)被初始化為null礁凡。
所有實(shí)例變量會(huì)生成一個(gè)隱式的getter方法,不是final或const的實(shí)例變量也會(huì)生成一個(gè)隱式的setter方法沿盅。
構(gòu)造函數(shù)
構(gòu)造函數(shù)不能被繼承把篓,如果不顯式提供子類的構(gòu)造函數(shù),系統(tǒng)就提供默認(rèn)的構(gòu)造函數(shù)腰涧。
class Base{
//父類構(gòu)造函數(shù)
Base(){
print("base init");
}
}
class Person extends Base{
var _name;
var _interest;
//默認(rèn)構(gòu)造函數(shù)
Person(){}
//命名構(gòu)造函數(shù)
Person.initNameAndAge(this._name,this._interest);
//重定向構(gòu)造函數(shù)
Person.initName(name):this.initNameAndAge(name,"無");
}
class RockerAddress {
final num lat;
final num lng;
//常量構(gòu)造函數(shù)
const RockerAddress(this.lat, this.lng);
static final RockerAddress address =
const RockerAddress(39.19, 141.32);
}
class Logger {
final String name;
bool isDebug = false;
// 命名構(gòu)造函數(shù)
Logger._internal(this.name);
// 緩存保存對(duì)象
static final Map<String, Logger> _cache = <String, Logger>{};
//工廠構(gòu)造函數(shù)
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = new Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
void log(String msg) {
if (!isDebug) {
print(msg);
}
}
}
void main() {
//person demo
var person = new Person();
var person1 = Person.initNameAndAge("xiaojian","pingpang");
var person2 = Person.initName("jim");
//rockaddress demo
var rockaddress = RockerAddress.address;
print(rockaddress.toString());
//logger demo
var p1 = new Logger("1");
p1.log("2");
var p2 = new Logger('22');
p2.log('3');
// 相同對(duì)象直接訪問緩存
var p3 = new Logger('1');
print(p1==p3);
}
運(yùn)行結(jié)果:
base init
base init
base init
Instance of 'RockerAddress'
2
3
true
- 默認(rèn)構(gòu)造函數(shù)
沒有聲明構(gòu)造函數(shù)韧掩,dart會(huì)提供默認(rèn)構(gòu)造函數(shù)。默認(rèn)構(gòu)造函數(shù)沒有參數(shù)窖铡,并且調(diào)用父類的無參數(shù)構(gòu)造函數(shù)疗锐。
- 命名構(gòu)造函數(shù)
使用命名構(gòu)造函數(shù)可以實(shí)現(xiàn)一個(gè)類多個(gè)構(gòu)造函數(shù)坊谁。構(gòu)造函數(shù)不能被繼承,父類中的命名構(gòu)造函數(shù)不能被子類繼承滑臊。如果想要子類也擁有一個(gè)父類一樣名字的構(gòu)造函數(shù)口芍,必須在子類實(shí)現(xiàn)這個(gè)構(gòu)造函數(shù)。
- 重定向構(gòu)造函數(shù)
有時(shí)候構(gòu)造函數(shù)的目的只是重定向到該類的另一個(gè)構(gòu)造函數(shù)雇卷。重定向構(gòu)造函數(shù)沒有函數(shù)體鬓椭,使用冒號(hào):分隔。
- 常量構(gòu)造函數(shù)
如果類的對(duì)象不會(huì)發(fā)生變化关划,可以構(gòu)造一個(gè)編譯時(shí)的常量構(gòu)造函數(shù)小染。定義格式如下:
定義所有的實(shí)例變量是final。
使用const聲明構(gòu)造函數(shù)贮折。
- 工廠構(gòu)造函數(shù)
當(dāng)實(shí)例化了一個(gè)構(gòu)造函數(shù)后裤翩,不想每次都創(chuàng)建該類的一個(gè)新的實(shí)例的時(shí)候使用factory關(guān)鍵字,定義工廠構(gòu)造函數(shù)调榄,從緩存中返回一個(gè)實(shí)例踊赠,或返回一個(gè)子類型的實(shí)例。
工廠構(gòu)造函數(shù)不能訪問this
- 初始化列表
除了調(diào)用父類的構(gòu)造函數(shù)每庆,也可以通過初始化列表 在子類的構(gòu)造函數(shù)體前(大括號(hào)前)來初始化實(shí)例的變量值筐带,使用逗號(hào),分隔。如下所示:
一個(gè)初始化器的右邊不能訪問this扣孟。
class Point {
num x;
num y;
Point(this.x, this.y);
// 在構(gòu)造函數(shù)體前 初始化列表 設(shè)置實(shí)例變量
Point.fromJson(Map jsonMap)
: x = jsonMap['x'],
y = jsonMap['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
- 調(diào)用父類的非默認(rèn)構(gòu)造函數(shù)
默認(rèn)情況下烫堤,子類調(diào)用父類的無參數(shù)的非命名構(gòu)造函數(shù)。父類的構(gòu)造函數(shù)會(huì)在子類的構(gòu)造函數(shù)體之前(大括號(hào)前)調(diào)用凤价。如果也使用了初始化列表 ,則會(huì)先執(zhí)行初始化列表 中的內(nèi)容拔创,即下面的順序:
初始化列表
父類無參數(shù)構(gòu)造函數(shù)
主類無參數(shù)構(gòu)造函數(shù)
如果父類不顯式提供無參的非命名構(gòu)造函數(shù)利诺,在子類中必須手動(dòng)調(diào)用父類的一個(gè)構(gòu)造函數(shù)。在子類構(gòu)造函數(shù)名后剩燥,大括號(hào){前慢逾,使用super.調(diào)用父類的構(gòu)造函數(shù),中間使用:分割灭红。
父類構(gòu)造函數(shù)參數(shù)不能訪問this侣滩,例如,參數(shù)可以調(diào)用靜態(tài)方法但不能調(diào)用實(shí)例方法变擒。
class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
// 父類沒有無參數(shù)的非命名構(gòu)造函數(shù)君珠,必須手動(dòng)調(diào)用一個(gè)構(gòu)造函數(shù) super.fromJson(data)
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
main() {
var emp = new Employee.fromJson({});
// Prints:
// in Person
// in Employee
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
}
抽象類
使用abstract關(guān)鍵字定義一個(gè)抽象類,抽象類不能實(shí)例化娇斑,抽象類通常用來定義接口策添,抽象類通常會(huì)包含一些抽象的方法材部。
//定義抽象類
abstract class Base{
//定義抽象方法
void doSomething();
}
方法
- 實(shí)例方法
Getters and setters
get()和set()方法是Dart 語言提供的專門用來讀取和寫入對(duì)象的屬性的方法。每一個(gè)類的實(shí)例變量都有一個(gè)隱式的getter和可能的setter(如果字段為final或const唯竹,只有g(shù)etter)乐导。
像++之類的操作符,無論是否明確定義了getter浸颓,都按預(yù)期的方式工作物臂。為了避免意想不到的副作用,操作符調(diào)用getter一次产上,將其值保存在臨時(shí)變量中棵磷。
class Rectangle {
num left;
num top;
num width;
num 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;
}
void main() {
var rect = new Rectangle(3, 4, 20, 15);
print(rect.left == 3);
rect.right = 12;
print(rect.left == -8);
}
運(yùn)行結(jié)果:
true
true
- 抽象方法
抽象方法,只有函數(shù)聲明蒂秘,沒有函數(shù)體泽本,作為接口在其他類中實(shí)現(xiàn)。調(diào)用抽象方法會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤姻僧。如果在不是抽象類中定義抽象方法會(huì)引發(fā)warning规丽,但不會(huì)阻止實(shí)例化。
abstract class Base{
//定義抽象方法
void doSomething();
}
class Child extends Base{
@override
void doSomething() {
print("test");
}
}
- 靜態(tài)變量和方法
使用static關(guān)鍵字來實(shí)現(xiàn)類范圍內(nèi)變量和方法撇贺。
靜態(tài)方法不能被實(shí)例調(diào)用赌莺,不能訪問this,只能被類名調(diào)用松嘶。
對(duì)于通用或廣泛使用的工具和功能艘狭,應(yīng)該使用頂級(jí)函數(shù),而不是靜態(tài)方法翠订。
可以使用靜態(tài)方法作為編譯時(shí)常量巢音。例如,可以給一個(gè)常量構(gòu)造函數(shù)尽超,傳遞一個(gè)靜態(tài)方法作為參數(shù)官撼。
class SecurityUtil{
//靜態(tài)變量
static const key = "Encryption key is generally static";
//靜態(tài)方法
static String md5(String){
}
}
隱式接口
每一個(gè)類都隱式的定義一個(gè)接口,這個(gè)接口包含了這個(gè)類的所有實(shí)例成員和它實(shí)現(xiàn)的所有接口似谁。
一個(gè)類可以實(shí)現(xiàn)一個(gè)或多個(gè)(用,隔開)接口傲绣,通過implements關(guān)鍵字。
class Person{
final _name;
Person(this._name);
String greet(who) => 'hello,$who,i am $_name';
}
//implements關(guān)鍵字
class Imposter implements Person {
final _name = '';
String greet(who) => 'hi $who.do you know who i am.';
}
greetBob(Person p) => p.greet('jim');
void main() {
print(greetBob(new Person('wangxiaojian')));
print(greetBob(new Imposter()));
}
運(yùn)行結(jié)果:
hello,jim,i am wangxiaojian
hi jim.do you know who i am.
繼承
使用extends來創(chuàng)造子類巩踏,使用super來指向父類秃诵。
子類可以重載實(shí)例方法,使用@override注解重載方法塞琼。
class Person {
final _name;
Person(this._name);
void printName() {
print("base name = $_name");
}
}
class Imposter extends Person {
Imposter(name) : super(name);
@override
void printName() {
print("child name = $_name");
}
}
void main() {
new Person("wangxiaojian").printName();
new Imposter("wangxiaojian").printName();
}
運(yùn)行結(jié)果:
base name = wangxiaojian
child name = wangxiaojian
枚舉類型
- 枚舉類型是一種特殊的類菠净,通常用來表示一組固定數(shù)字的常量值。
使用enum關(guān)鍵字聲明枚舉類型。 - 每個(gè)枚舉類型都有一個(gè)index嗤练,返回以0開始的位置索引榛了,每次加1
- 使用values關(guān)鍵字獲取枚舉的所有值,返回一個(gè)列表煞抬。
- 不能繼承霜大,mixin,或?qū)崿F(xiàn)一個(gè)枚舉;不能顯式的實(shí)例化一個(gè)枚舉革答。
enum Week {
Monday,
Tuesday,
wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
void main() {
print(Week.Monday.index ==0);
print(Week.Tuesday.index ==1);
print(Week.wednesday.index ==4);
}
運(yùn)行結(jié)果:
true
true
false
[Week.Monday, Week.Tuesday, Week.wednesday, Week.Thursday, Week.Friday, Week.Saturday, Week.Sunday]
minxins
mixins是一種在多個(gè)類層次結(jié)構(gòu)中战坤,重用一個(gè)類的代碼的方法。使用with關(guān)鍵字后跟多個(gè)mixin名残拐。
class Speak{
void speak(){
print(this.runtimeType.toString()+" speak");
}
}
class Walk{
void walk(){
print(this.runtimeType.toString()+ " walk");
}
}
class Base{
}
class Person extends Base with Speak,Walk{
}
class Animal extends Base with Speak,Walk{
}
void main() {
new Person().speak();
new Animal().walk();
}
運(yùn)行結(jié)果:
Person speak
Animal walk