Flutter開(kāi)發(fā)(2)- Dart語(yǔ)言(2)

一. 運(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í)不講解這種方式借尿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市屉来,隨后出現(xiàn)的幾起案子路翻,更是在濱河造成了極大的恐慌,老刑警劉巖茄靠,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帚桩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嘹黔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)莫瞬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)儡蔓,“玉大人,你說(shuō)我怎么就攤上這事疼邀∥菇” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵旁振,是天一觀(guān)的道長(zhǎng)获询。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拐袜,這世上最難降的妖魔是什么吉嚣? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮蹬铺,結(jié)果婚禮上尝哆,老公的妹妹穿的比我還像新娘。我一直安慰自己甜攀,他們只是感情好秋泄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布琐馆。 她就那樣靜靜地躺著,像睡著了一般恒序。 火紅的嫁衣襯著肌膚如雪瘦麸。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天歧胁,我揣著相機(jī)與錄音滋饲,去河邊找鬼。 笑死与帆,一個(gè)胖子當(dāng)著我的面吹牛了赌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玄糟,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼勿她,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了阵翎?” 一聲冷哼從身側(cè)響起逢并,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎郭卫,沒(méi)想到半個(gè)月后砍聊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贰军,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年玻蝌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片词疼。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俯树,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贰盗,到底是詐尸還是另有隱情许饿,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布舵盈,位于F島的核電站陋率,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏秽晚。R本人自食惡果不足惜瓦糟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赴蝇。 院中可真熱鬧狸页,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至斋竞,卻和暖如春倔约,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坝初。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工浸剩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鳄袍。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓绢要,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拗小。 傳聞我的和親對(duì)象是個(gè)殘疾皇子重罪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容