一. 運(yùn)算符
????這里,我只列出來(lái)相對(duì)其他語(yǔ)言比較特殊的運(yùn)算符,因?yàn)槟承┻\(yùn)算符太簡(jiǎn)單了焦除,不浪費(fèi)時(shí)間,比如+虐杯、-、+=昧港、==擎椰。
????你可能會(huì)疑惑,Dart為什么要搞出這么多特殊的運(yùn)算符呢创肥?
????你要堅(jiān)信一點(diǎn):所有這些特殊的運(yùn)算符都是為了讓我們?cè)陂_(kāi)發(fā)中可以更加方便的操作达舒,而不是讓我們的編碼變得更加復(fù)雜值朋。
1.1. 除法、整除巩搏、取模運(yùn)算
????我們來(lái)看一下除法昨登、整除、取模運(yùn)算
????var num = 7;
????print(num / 3); // 除法操作, 結(jié)果2.3333..
????print(num ~/ 3); // 整除操作, 結(jié)果2;
????print(num % 3); // 取模操作, 結(jié)果1;
1.2. ??=賦值操作
????dart有一個(gè)很多語(yǔ)言都不具備的賦值運(yùn)算符:
????當(dāng)變量為null時(shí)贯底,使用后面的內(nèi)容進(jìn)行賦值篙骡。
????當(dāng)變量有值時(shí),使用自己原來(lái)的值丈甸。
main(List<String> args) {??
????var name1 = 'coderwhy';??
????print(name1);??
????// var name2 = 'kobe';??
????var name2 = null;??
????name2 ??= 'james';??
?????print(name2); // 當(dāng)name2初始化為kobe時(shí),結(jié)果為kobe尿褪,當(dāng)初始化為null時(shí)睦擂,賦值了james}
1.3. 條件運(yùn)算符:
????Dart中包含一直比較特殊的條件運(yùn)算符:expr1 ?? expr2
????如果expr1是null,則返回expr2的結(jié)果;
????如果expr1不是null杖玲,直接使用expr1的結(jié)果顿仇。
var temp = 'why';
var temp = null;
var name = temp ?? 'kobe';
print(name);
1.4. 級(jí)聯(lián)語(yǔ)法:..
某些時(shí)候,我們希望對(duì)一個(gè)對(duì)象進(jìn)行連續(xù)的操作摆马,這個(gè)時(shí)候可以使用級(jí)聯(lián)語(yǔ)法
class Person {??
????String name;??
????void run() {? ??
????????print("${name} is running");??
????}??
????void eat() {? ??
????????print("${name} is eating");??
????}??
????void swim() {? ??
????????print("${name} is swimming");??
????}
}
main(List<String> args) {??
????final p1 = Person();??
????p1.name = 'why';??
????p1.run();? p1.eat();??
????p1.swim();??
????final p2 = Person()..name = "why" ? ? ? ? ? ? ?
????????????????????????????????????????????..run() ?..eat() ..swim();
}
二. 流程控制
????和大部分語(yǔ)言的特性比較相似臼闻,這里就不再詳細(xì)贅述,看一下即可囤采。
2.1. if和else
????和其他語(yǔ)言用法一樣
????這里有一個(gè)注意點(diǎn):不支持非空即真或者非0即真述呐,必須有明確的bool類(lèi)型
????我們來(lái)看下面name為null的判斷
2.2. 循環(huán)操作
基本的for循環(huán)
for (var i = 0; i < 5; i++) {
? print(i);
}
for in遍歷List和Set類(lèi)型
var names = ['why', 'kobe', 'curry'];
for (var name in names) {
? print(name);
}
while和do-while和其他語(yǔ)言一致
break和continue用法也是一致
2.3. switch-case
普通的switch使用
注意:每一個(gè)case語(yǔ)句,默認(rèn)情況下必須以一個(gè)break結(jié)尾
main(List<String> args) {
? var direction = 'east';
? switch (direction) {
? ? case 'east':
? ? ? print('東面');
? ? ? break;
? ? case 'south':
? ? ? print('南面');
? ? ? break;
? ? case 'west':
? ? ? print('西面');
? ? ? break;
? ? case 'north':
? ? ? print('北面');
? ? ? break;
? ? default:
? ? ? print('其他方向');
? }
}
三. 類(lèi)和對(duì)象
????Dart是一個(gè)面向?qū)ο蟮恼Z(yǔ)言蕉毯,面向?qū)ο笾蟹浅V匾母拍罹褪穷?lèi)乓搬,類(lèi)產(chǎn)生了對(duì)象。
????這一節(jié)代虾,我們就具體來(lái)學(xué)習(xí)類(lèi)和對(duì)象进肯,但是Dart對(duì)類(lèi)進(jìn)行了很多其他語(yǔ)言沒(méi)有的特性,所以棉磨,這里我會(huì)花比較長(zhǎng)的篇幅來(lái)講解江掩。
3.1. 類(lèi)的定義
在Dart中,定義類(lèi)用class關(guān)鍵字乘瓤。
類(lèi)通常有兩部分組成:成員(member)和方法(method)环形。
定義類(lèi)的偽代碼如下:
class 類(lèi)名 {
? 類(lèi)型 成員名;
? 返回值類(lèi)型 方法名(參數(shù)列表) {
? ? 方法體
? }
}
編寫(xiě)一個(gè)簡(jiǎn)單的Person類(lèi):
????這里有一個(gè)注意點(diǎn): 我們?cè)诜椒ㄖ惺褂脤傩?成員/實(shí)例變量)時(shí),并沒(méi)有加this馅扣;
????Dart的開(kāi)發(fā)風(fēng)格中斟赚,在方法中通常使用屬性時(shí),會(huì)省略this差油,但是有命名沖突時(shí)拗军,this不能省略任洞;
class Person {
? String name;
? eat() {
? ? print('$name在吃東西');
? }
}
我們來(lái)使用這個(gè)類(lèi),創(chuàng)建對(duì)應(yīng)的對(duì)象:
注意:從Dart2開(kāi)始发侵,new關(guān)鍵字可以省略交掏。
main(List<String> args) {
? // 1.創(chuàng)建類(lèi)的對(duì)象
? var p = new Person(); // 直接使用Person()也可以創(chuàng)建
? // 2.給對(duì)象的屬性賦值
? p.name = 'why';
? // 3.調(diào)用對(duì)象的方法
? p.eat();
}
3.2. 構(gòu)造方法
3.2.1. 普通構(gòu)造方法
????我們知道, 當(dāng)通過(guò)類(lèi)創(chuàng)建一個(gè)對(duì)象時(shí),會(huì)調(diào)用這個(gè)類(lèi)的構(gòu)造方法刃鳄。
????當(dāng)類(lèi)中沒(méi)有明確指定構(gòu)造方法時(shí)盅弛,將默認(rèn)擁有一個(gè)無(wú)參的構(gòu)造方法。
????前面的Person中我們就是在調(diào)用這個(gè)構(gòu)造方法.
????我們也可以根據(jù)自己的需求叔锐,定義自己的構(gòu)造方法:
**注意一:**當(dāng)有了自己的構(gòu)造方法時(shí)挪鹏,默認(rèn)的構(gòu)造方法將會(huì)失效,不能使用
????當(dāng)然愉烙,你可能希望明確的寫(xiě)一個(gè)默認(rèn)的構(gòu)造方法讨盒,但是會(huì)和我們自定義的構(gòu)造方法沖突;
????這是因?yàn)镈art本身不支持函數(shù)的重載(名稱(chēng)相同, 參數(shù)不同的方式)步责。
**注意二:**這里我還實(shí)現(xiàn)了toString方法
class Person {
? String name;
? int age;
? Person(String name, int age) {
? ? this.name = name;
? ? this.age = age;
? }
? @override
? String toString() {
? ? return 'name=$name age=$age';
? }
}
另外返顺,在實(shí)現(xiàn)構(gòu)造方法時(shí),通常做的事情就是通過(guò)**參數(shù)給屬性**賦值
為了簡(jiǎn)化這一過(guò)程, Dart提供了一種更加簡(jiǎn)潔的語(yǔ)法糖形式.
上面的構(gòu)造方法可以?xún)?yōu)化成下面的寫(xiě)法:
? Person(String name, int age) {
? ? this.name = name;
? ? this.age = age;
? }
? // 等同于
? Person(this.name, this.age);
3.2.2. 命名構(gòu)造方法
????但是在開(kāi)發(fā)中, 我們確實(shí)希望實(shí)現(xiàn)更多的構(gòu)造方法蔓肯,怎么辦呢遂鹊?
????因?yàn)椴恢С址椒ǎê瘮?shù))的重載,所以我們沒(méi)辦法創(chuàng)建相同名稱(chēng)的構(gòu)造方法蔗包。
我們需要使用命名構(gòu)造方法:
class Person {
? String name;
? int age;
? Person() {
? ? name = '';
? ? age = 0;
? }
// 命名構(gòu)造方法
? Person.withArgments(String name, int age) {
? ? this.name = name;
? ? this.age = age;
? }
? @override
? String toString() {
? ? return 'name=$name age=$age';
? }
}
// 創(chuàng)建對(duì)象
var p1 = new Person();
print(p1);
var p2 = new Person.withArgments('why', 18);
print(p2);
在之后的開(kāi)發(fā)中, 我們也可以利用命名構(gòu)造方法秉扑,提供更加便捷的創(chuàng)建對(duì)象方式:
比如開(kāi)發(fā)中,我們需要經(jīng)常將一個(gè)Map轉(zhuǎn)成對(duì)象气忠,可以提供如下的構(gòu)造方法
? // 新的構(gòu)造方法
Person.fromMap(Map<String, Object> map) {
? ? this.name = map['name'];
? ? this.age = map['age'];
? }
// 通過(guò)上面的構(gòu)造方法創(chuàng)建對(duì)象
? var p3 = new Person.fromMap({'name': 'kobe', 'age': 30});
? print(p3);
3.2.3. 初始化列表
我們來(lái)重新定義一個(gè)類(lèi)Point, 傳入x/y邻储,可以得到它們的距離distance:
class Point {
? final num x;
? final num y;
? final num distance;
? // 錯(cuò)誤寫(xiě)法
? // Point(this.x, this.y) {
? //? distance = sqrt(x * x + y * y);
? // }
? // 正確的寫(xiě)法
? Point(this.x, this.y) : distance = sqrt(x * x + y * y);
}
上面這種初始化變量的方法, 我們稱(chēng)之為初始化列表(Initializer list)
3.2.4. 重定向構(gòu)造方法
????在某些情況下, 我們希望在一個(gè)構(gòu)造方法中去調(diào)用另外一個(gè)構(gòu)造方法, 這個(gè)時(shí)候可以使用重定向構(gòu)造方法:
????在一個(gè)構(gòu)造函數(shù)中,去調(diào)用另外一個(gè)構(gòu)造函數(shù)(注意:是在冒號(hào)后面使用this調(diào)用)
class Person {
? String name;
? int age;
? Person(this.name, this.age);
? Person.fromName(String name) : this(name, 0);
}
3.2.5. 常量構(gòu)造方法
????在某些情況下旧噪,傳入相同值時(shí)吨娜,我們希望返回同一個(gè)對(duì)象,這個(gè)時(shí)候淘钟,可以使用常量構(gòu)造方法.
????默認(rèn)情況下宦赠,創(chuàng)建對(duì)象時(shí),即使傳入相同的參數(shù)米母,創(chuàng)建出來(lái)的也不是同一個(gè)對(duì)象勾扭,看下面代碼:
這里我們使用identical(對(duì)象1, 對(duì)象2)函數(shù)來(lái)判斷兩個(gè)對(duì)象是否是同一個(gè)對(duì)象:
main(List<String> args) {
? var p1 = Person('why');
? var p2 = Person('why');
? print(identical(p1, p2)); // false
}
class Person {
? String name;
? Person(this.name);
}
????但是, 如果將構(gòu)造方法前加const進(jìn)行修飾,那么可以保證同一個(gè)參數(shù)铁瞒,創(chuàng)建出來(lái)的對(duì)象是相同的
????這樣的構(gòu)造方法就稱(chēng)之為常量構(gòu)造方法妙色。
main(List<String> args) {
? var p1 = const Person('why');
? var p2 = const Person('why');
? print(identical(p1, p2)); // true
}
class Person {
? final String name;
? const Person(this.name);
}
常量構(gòu)造方法有一些注意點(diǎn):
????注意一:擁有常量構(gòu)造方法的類(lèi)中,所有的成員變量必須是final修飾的.
????注意二: 為了可以通過(guò)常量構(gòu)造方法慧耍,創(chuàng)建出相同的對(duì)象身辨,不再使用 new關(guān)鍵字丐谋,而是使用const關(guān)鍵字
????如果是將結(jié)果賦值給const修飾的標(biāo)識(shí)符時(shí),const可以省略.
3.2.6. 工廠(chǎng)構(gòu)造方法
Dart提供了factory關(guān)鍵字, 用于通過(guò)工廠(chǎng)去獲取對(duì)象
main(List<String> args) {
? var p1 = Person('why');
? var p2 = Person('why');
? print(identical(p1, p2)); // true
}
class Person {
? String name;
? static final Map<String, Person> _cache = <String, Person>{};
? factory Person(String name) {
? ? if (_cache.containsKey(name)) {
? ? ? return _cache[name];
? ? } else {
? ? ? final p = Person._internal(name);
? ? ? _cache[name] = p;
? ? ? return p;
? ? }
? }
? Person._internal(this.name);
}
3.3. setter和getter
????默認(rèn)情況下煌珊,Dart中類(lèi)定義的屬性是可以直接被外界訪(fǎng)問(wèn)的号俐。
????但是某些情況下,我們希望監(jiān)控這個(gè)類(lèi)的屬性被訪(fǎng)問(wèn)的過(guò)程定庵,這個(gè)時(shí)候就可以使用setter和getter了
main(List<String> args) {
? final d = Dog("黃色");
? d.setColor = "黑色";
? print(d.getColor);
}
class Dog {
? String color;
? String get getColor {
? ? return color;
? }
? set setColor(String color) {
? ? this.color = color;
? }
? Dog(this.color);
}
3.4. 類(lèi)的繼承
????面向?qū)ο蟮钠渲幸淮筇匦跃褪抢^承吏饿,繼承不僅僅可以減少我們的代碼量,也是多態(tài)的使用前提蔬浙。
????Dart中的繼承使用extends關(guān)鍵字猪落,子類(lèi)中使用super來(lái)訪(fǎng)問(wèn)父類(lèi)。
????父類(lèi)中的所有成員變量和方法都會(huì)被繼承,畴博,但是構(gòu)造方法除外许布。
main(List<String> args) {
? var p = new Person();
? p.age = 18;
? p.run();
? print(p.age);
}
class Animal {
? int age;
? run() {
? ? print('在奔跑ing');
? }
}
class Person extends Animal {
}
子類(lèi)可以擁有自己的成員變量, 并且可以對(duì)父類(lèi)的方法進(jìn)行重寫(xiě):
class Person extends Animal {
? String name;
? @override
? run() {
? ? print('$name在奔跑ing');
? }
}
子類(lèi)中可以調(diào)用父類(lèi)的構(gòu)造方法,對(duì)某些屬性進(jìn)行初始化:
????子類(lèi)的構(gòu)造方法在執(zhí)行前绎晃,將隱含調(diào)用父類(lèi)的無(wú)參默認(rèn)構(gòu)造方法(沒(méi)有參數(shù)且與類(lèi)同名的構(gòu)造方法)。
????如果父類(lèi)沒(méi)有無(wú)參默認(rèn)構(gòu)造方法杂曲,則子類(lèi)的構(gòu)造方法必須在初始化列表中通過(guò)super顯式調(diào)用父類(lèi)的某個(gè)構(gòu)造方法庶艾。
class Animal {
? int age;
? Animal(this.age);
? run() {
? ? print('在奔跑ing');
? }
}
class Person extends Animal {
? String name;
? Person(String name, int age) : name=name, super(age);
? @override
? run() {
? ? print('$name在奔跑ing');
? }
? @override
? String toString() {
? ? return 'name=$name, age=$age';
? }
}
3.5. 抽象類(lèi)
????我們知道,繼承是多態(tài)使用的前提擎勘。
????所以在定義很多通用的**調(diào)用接口**時(shí), 我們通常會(huì)讓調(diào)用者傳入父類(lèi)咱揍,通過(guò)多態(tài)來(lái)實(shí)現(xiàn)更加靈活的調(diào)用方式。
????但是棚饵,父類(lèi)本身可能并不需要對(duì)某些方法進(jìn)行具體的實(shí)現(xiàn)煤裙,所以父類(lèi)中定義的方法,,我們可以定義為抽象方法噪漾。
????什么是 抽象方法? 在Dart中沒(méi)有具體實(shí)現(xiàn)的方法(沒(méi)有方法體)硼砰,就是抽象方法。
????????抽象方法欣硼,必須存在于抽象類(lèi)中题翰。
????????抽象類(lèi)是使用abstract聲明的類(lèi)。
下面的代碼中, Shape類(lèi)就是一個(gè)抽象類(lèi), 其中包含一個(gè)抽象方法.
abstract class Shape {
? getArea();
}
class Circle extends Shape {
? double r;
? Circle(this.r);
? @override
? getArea() {
? ? return r * r * 3.14;
? }
}
class Reactangle extends Shape {
? double w;
? double h;
? Reactangle(this.w, this.h);
? @override
? getArea() {
? ? return w * h;
? }
}
注意事項(xiàng):
????**注意一:**抽象類(lèi)不能實(shí)例化.
????**注意二:**抽象類(lèi)中的抽象方法必須被子類(lèi)實(shí)現(xiàn), 抽象類(lèi)中的已經(jīng)被實(shí)現(xiàn)方法, 可以不被子類(lèi)重寫(xiě).
3.6. 隱式接口
????Dart中的接口比較特殊, 沒(méi)有一個(gè)專(zhuān)門(mén)的關(guān)鍵字來(lái)聲明接口.
????默認(rèn)情況下诈胜,定義的每個(gè)類(lèi)都相當(dāng)于默認(rèn)也聲明了一個(gè)接口豹障,可以由其他的類(lèi)來(lái)實(shí)現(xiàn)(因?yàn)镈art不支持多繼承)
????在開(kāi)發(fā)中,我們通常將用于給別人實(shí)現(xiàn)的類(lèi)聲明為抽象類(lèi):
abstract class Runner {
? run();
}
abstract class Flyer {
? fly();
}
class SuperMan implements Runner, Flyer {
? @override
? run() {
? ? print('超人在奔跑');
? }
? @override
? fly() {
? ? print('超人在飛');
? }
}
3.7. Mixin混入
????在通過(guò)implements實(shí)現(xiàn)某個(gè)類(lèi)時(shí)焦匈,類(lèi)中所有的方法都必須被重新實(shí)現(xiàn)(無(wú)論這個(gè)類(lèi)原來(lái)是否已經(jīng)實(shí)現(xiàn)過(guò)該方法)血公。
????但是某些情況下,一個(gè)類(lèi)可能希望直接復(fù)用之前類(lèi)的原有實(shí)現(xiàn)方案缓熟,怎么做呢?
????????使用繼承嗎累魔?但是Dart只支持單繼承摔笤,那么意味著你只能復(fù)用一個(gè)類(lèi)的實(shí)現(xiàn)。
????Dart提供了另外一種方案: Mixin混入的方式
????????除了可以通過(guò)class定義類(lèi)之外薛夜,也可以通過(guò)mixin關(guān)鍵字來(lái)定義一個(gè)類(lèi)籍茧。
????????只是通過(guò)mixin定義的類(lèi)用于被其他類(lèi)混入使用,通過(guò)with關(guān)鍵字來(lái)進(jìn)行混入梯澜。
main(List<String> args) {
? var superMan = SuperMain();
? superMan.run();
? superMan.fly();
}
mixin Runner {
? run() {
? ? print('在奔跑');
? }
}
mixin Flyer {
? fly() {
? ? print('在飛翔');
? }
}
// implements的方式要求必須對(duì)其中的方法進(jìn)行重新實(shí)現(xiàn)
// class SuperMan implements Runner, Flyer {}
class SuperMain with Runner, Flyer {
}
3.8. 類(lèi)成員和方法
????前面我們?cè)陬?lèi)中定義的成員和方法都屬于對(duì)象級(jí)別的, 在開(kāi)發(fā)中, 我們有時(shí)候也需要定義類(lèi)級(jí)別的成員和方法
????在Dart中我們使用static關(guān)鍵字來(lái)定義:
main(List<String> args) {
? var stu = Student();
? stu.name = 'why';
? stu.sno = 110;
? stu.study();
? Student.time = '早上8點(diǎn)';
? // stu.time = '早上9點(diǎn)'; 錯(cuò)誤做法, 實(shí)例對(duì)象不能訪(fǎng)問(wèn)類(lèi)成員?
? Student.attendClass();? // stu.attendClass(); 錯(cuò)誤做法, 實(shí)現(xiàn)對(duì)象不能訪(fǎng)問(wèn)類(lèi)方法
}
class Student {
? String name;
? int sno;
? static String time;
? study() {
? ? print('$name在學(xué)習(xí)');
? }
? static attendClass() {
? ? print('去上課');
? }
}
3.9. 枚舉類(lèi)型
????枚舉在開(kāi)發(fā)中也非常常見(jiàn), 枚舉也是一種特殊的類(lèi), 通常用于表示固定數(shù)量的常量值寞冯。
3.9.1. 枚舉的定義
枚舉使用enum關(guān)鍵字來(lái)進(jìn)行定義:
main(List<String> args) {
? print(Colors.red);
}
enum Colors {
? red,
? green,
? blue
}
3.9.2. 枚舉的屬性
?枚舉類(lèi)型中有兩個(gè)比較常見(jiàn)的屬性:
index: 用于表示每個(gè)枚舉常量的索引, 從0開(kāi)始.
values: 包含每個(gè)枚舉值的List.
main(List<String> args) {
? print(Colors.red.index);
? print(Colors.green.index);
? print(Colors.blue.index);
? print(Colors.values);
}
enum Colors {
? red,
? green,
? blue
}
枚舉類(lèi)型的注意事項(xiàng):
????注意一: 您不能子類(lèi)化、混合或?qū)崿F(xiàn)枚舉晚伙。
????注意二: 不能顯式實(shí)例化一個(gè)枚舉
四. 泛型
4.1. 為什么使用泛型?
????對(duì)于有基礎(chǔ)的同學(xué), 這部分不再解釋
4.2. List和Map的泛型
List使用時(shí)的泛型寫(xiě)法:
? // 創(chuàng)建List的方式
? var names1 = ['why', 'kobe', 'james', 111];
? print(names1.runtimeType); // List<Object>
? // 限制類(lèi)型
? var names2 = <String>['why', 'kobe', 'james', 111]; // 最后一個(gè)報(bào)錯(cuò)
? List<String> names3 = ['why', 'kobe', 'james', 111]; // 最后一個(gè)報(bào)錯(cuò)
Map使用時(shí)的泛型寫(xiě)法:
? // 創(chuàng)建Map的方式
? var infos1 = {1: 'one', 'name': 'why', 'age': 18};
? print(infos1.runtimeType); // _InternalLinkedHashMap<Object, Object>
? // 對(duì)類(lèi)型進(jìn)行顯示
? Map<String, String> infos2 = {'name': 'why', 'age': 18}; // 18不能放在value中
? var infos3 = <String, String>{'name': 'why', 'age': 18}; // 18不能放在value中
4.3. 類(lèi)定義的泛型
????如果我們需要定義一個(gè)類(lèi), 用于存儲(chǔ)位置信息Location, 但是并不確定使用者希望使用的是int類(lèi)型,還是double類(lèi)型,? 甚至是一個(gè)字符串, 這個(gè)時(shí)候如何定義呢?
一種方案是使用Object類(lèi)型, 但是在之后使用時(shí), 非常不方便
另一種方案就是使用泛型.
Location類(lèi)的定義: Object方式
main(List<String> args) {
? Location l1 = Location(10, 20);
? print(l1.x.runtimeType); // Object
}
class Location {
? Object x;
? Object y;
? Location(this.x, this.y);
}
Location類(lèi)的定義: 泛型方式
main(List<String> args) {
? Location l2 = Location<int>(10, 20);
? print(l2.x.runtimeType); // int
? Location l3 = Location<String>('aaa', 'bbb');
? print(l3.x.runtimeType); // String
}
}
class Location<T> {
? T x;
? T y;
? Location(this.x, this.y);
}
如果我們希望類(lèi)型只能是num類(lèi)型, 怎么做呢?
main(List<String> args) {
? Location l2 = Location<int>(10, 20);
? print(l2.x.runtimeType);
? // 錯(cuò)誤的寫(xiě)法, 類(lèi)型必須繼承自num
? Location l3 = Location<String>('aaa', 'bbb');
? print(l3.x.runtimeType);
}
class Location<T extends num> {
? T x;
? T y;
? Location(this.x, this.y);
}
4.4. 泛型方法的定義
最初吮龄,Dart僅僅在類(lèi)中支持泛型。后來(lái)一種稱(chēng)為泛型方法的新語(yǔ)法允許在方法和函數(shù)中使用類(lèi)型參數(shù)咆疗。
main(List<String> args) {
? var names = ['why', 'kobe'];
? var first = getFirst(names);
? print('$first ${first.runtimeType}'); // why String
}
T getFirst<T>(List<T> ts) {
? return ts[0];
}
五. 庫(kù)的使用
????在Dart中漓帚,你可以導(dǎo)入一個(gè)庫(kù)來(lái)使用它所提供的功能。
????庫(kù)的使用可以使代碼的重用性得到提高午磁,并且可以更好的組合代碼尝抖。
????Dart中任何一個(gè)dart文件都是一個(gè)庫(kù),即使你沒(méi)有用關(guān)鍵字library聲明
5.1. 庫(kù)的導(dǎo)入
????import語(yǔ)句用來(lái)導(dǎo)入一個(gè)庫(kù)迅皇,后面跟一個(gè)字符串形式的Uri來(lái)指定表示要引用的庫(kù)昧辽,語(yǔ)法如下:
????????import '庫(kù)所在的uri';
常見(jiàn)的庫(kù)URI有三種不同的形式
來(lái)自dart標(biāo)準(zhǔn)版,比如dart:io登颓、dart:html搅荞、dart:math、dart:core(但是這個(gè)可以省略)
????//dart:前綴表示Dart的標(biāo)準(zhǔn)庫(kù)框咙,如dart:io咕痛、dart:html、dart:math
????import 'dart:io';
使用相對(duì)路徑導(dǎo)入的庫(kù)喇嘱,通常指自己項(xiàng)目中定義的其他dart文件
????//當(dāng)然茉贡,你也可以用相對(duì)路徑或絕對(duì)路徑的dart文件來(lái)引用
????import 'lib/student/student.dart';
Pub包管理工具管理的一些庫(kù),包括自己的配置以及一些第三方的庫(kù)者铜,通常使用前綴package
????//Pub包管理系統(tǒng)中有很多功能強(qiáng)大块仆、實(shí)用的庫(kù),可以使用前綴 package:
????import 'package:flutter/material.dart';
庫(kù)文件中內(nèi)容的顯示和隱藏
如果希望只導(dǎo)入庫(kù)中某些內(nèi)容王暗,或者刻意隱藏庫(kù)里面某些內(nèi)容悔据,可以使用show和hide關(guān)鍵字
????**show關(guān)鍵字:**可以顯示某個(gè)成員(屏蔽其他)
????**hide關(guān)鍵字:**可以隱藏某個(gè)成員(顯示其他)
import 'lib/student/student.dart' show Student, Person;
import 'lib/student/student.dart' hide Person;
庫(kù)中內(nèi)容和當(dāng)前文件中的名字沖突
????當(dāng)各個(gè)庫(kù)有命名沖突的時(shí)候,可以使用as關(guān)鍵字來(lái)使用命名空間
????????import 'lib/student/student.dart' as Stu;
????????Stu.Student s = new Stu.Student();
5.2. 庫(kù)的定義
library關(guān)鍵字
????通常在定義庫(kù)時(shí)俗壹,我們可以使用library關(guān)鍵字給庫(kù)起一個(gè)名字科汗。
????但目前我發(fā)現(xiàn),庫(kù)的名字并不影響導(dǎo)入绷雏,因?yàn)閕mport語(yǔ)句用的是字符串URI
????library math;
part關(guān)鍵字
????在之前我們使用student.dart作為演練的時(shí)候头滔,只是將該文件作為一個(gè)庫(kù)怖亭。
????在開(kāi)發(fā)中,如果一個(gè)庫(kù)文件太大坤检,將所有內(nèi)容保存到一個(gè)文件夾是不太合理的兴猩,我們有可能希望將這個(gè)庫(kù)進(jìn)行拆分,這個(gè)時(shí)候就可以使用part關(guān)鍵字了
????不過(guò)官方已經(jīng)不建議使用這種方式了:
????????https://dart.dev/guides/libraries/create-library-packages
mathUtils.dart文件
part of "utils.dart";
int sum(int num1, int num2) {
? return num1 + num2;
}
dateUtils.dart文件
part of "utils.dart";
String dateFormat(DateTime date) {
? return "2020-12-12";
}
utils.dart文件
part "mathUtils.dart";
part "dateUtils.dart";
test_libary.dart文件
import "lib/utils.dart";
main(List<String> args) {
? print(sum(10, 20));
? print(dateFormat(DateTime.now()));
}
export關(guān)鍵字
官方不推薦使用part關(guān)鍵字早歇,那如果庫(kù)非常大倾芝,如何進(jìn)行管理呢?
????將每一個(gè)dart文件作為庫(kù)文件箭跳,使用export關(guān)鍵字在某個(gè)庫(kù)文件中單獨(dú)導(dǎo)入
mathUtils.dart文件
int sum(int num1, int num2) {
? return num1 + num2;
}
dateUtils.dart文件
String dateFormat(DateTime date) {
? return "2020-12-12";
}
utils.dart文件
library utils;
export "mathUtils.dart";
export "dateUtils.dart";
test_libary.dart文件
import "lib/utils.dart";
main(List<String> args) {
? print(sum(10, 20));
? print(dateFormat(DateTime.now()));
}
????最后晨另,也可以通過(guò)Pub管理自己的庫(kù)自己的庫(kù),在項(xiàng)目開(kāi)發(fā)中個(gè)人覺(jué)得不是非常有必要谱姓,所以暫時(shí)不講解這種方式借尿。