Dart基礎(chǔ)(一)

基礎(chǔ)類型

Number類型

Number中包含了兩個(gè)類型intdouble。分別代表整數(shù)類型和雙精度浮點(diǎn)類型。

  • int
    int 類型在不同的環(huán)境中長(zhǎng)度并不一樣,在DartVM上,int的范圍是-2^63 至 2^63 - 1,而在web中,int的范圍是-2^53 至 2^53 - 1
    定義int型變量可以通過(guò)以下幾種方式,其中通過(guò)var來(lái)定義變量,可以不需要指定類型,編譯器可根據(jù)字面量進(jìn)行推斷。
int a = 1;
int b = 0xDEFF0;
var c = 2;

注意:通過(guò)int類型來(lái)定義變量時(shí),如果定義的是全局變量一定要賦值(或聲明late),否則編譯器會(huì)報(bào)錯(cuò)。如果是定義局部變量,則在使用前必須賦值,否則使用時(shí)會(huì)拋出異常。這是因?yàn)樵赿art的空安全機(jī)制的限制。

  • double
    double 64位雙精度浮點(diǎn)數(shù)字。
    定義double變量,可通過(guò)以下方式,如果顯示的申明變量類型是double,字面量為整形時(shí),必要時(shí)會(huì)自動(dòng)轉(zhuǎn)換成double
    var a = 1.0;
    double b = 2.0;
    double c = 1; 

其他

Number類型的變量都支持基本的運(yùn)算符+ - * /等,還有ceil() abs() floor()等方法。整型支持傳統(tǒng)的位移操作,比如移位(<<、>>>>>)、補(bǔ)碼 (~)、按位與 (&)、按位或 (|) 以及按位異或 (^)。

print((3 << 1) == 6); // true; 0011 << 1 == 0110
print((3 | 4) == 7); // true; 0011 | 0100 == 0111
print((3 & 4) == 0); // true; 0011 & 0100 == 0000

String

Dart中的字符串包含了 UTF-16 編碼的字符序列??梢允褂脝我?hào)或者雙引號(hào)來(lái)創(chuàng)建字符串

var str1 = '我是一個(gè)字符串';
var str2 = "我也是一個(gè)字符串"

'"的區(qū)別:在'中需要使用\來(lái)轉(zhuǎn)義那些與單引號(hào)沖突的字符:

var str1 = 'it\'s easy to escape the string delimiter';

模版字符串

在字符串中,請(qǐng)以 ${表達(dá)式} 的形式使用表達(dá)式,如果表達(dá)式是一個(gè)標(biāo)識(shí)符,可以省略掉 {}。如果表達(dá)式的結(jié)果為一個(gè)對(duì)象,則 Dart 會(huì)調(diào)用該對(duì)象的 toString 方法來(lái)獲取一個(gè)字符串。

var s = 'string interpolation';
print('Dart has $s, which is very handy.' ==
    'Dart has string interpolation, '
        'which is very handy.'); // true
print('That deserves all caps. '
        '${s.toUpperCase()} is very handy!' ==
    'That deserves all caps. '
        'STRING INTERPOLATION is very handy!'); // true

字符串字面量是一個(gè)編譯時(shí)常量,只要是編譯時(shí)常量 (null、數(shù)字、字符串、布爾) 都可以作為字符串字面量的插值表達(dá)式:

// 這里定義為常量是可行的
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// 非常量的字符串是不被允許使用在定義字符串的模版內(nèi)
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';

字符串拼接

我們可以使用+號(hào)或者并列放置在多行的字符串來(lái)拼接字符串。

var str1 = 'the + operate' + ' works';
var str2 = 'String '
    'concatenation'
    " works even over line breaks.";

多行字符串

使用三個(gè)' 或者三個(gè)"來(lái)定義多行字符串

var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";

raw字符串

通過(guò)在字符串前加上r做前綴可創(chuàng)建raw字符串,即字符串不會(huì)被做任何處理(如轉(zhuǎn)義)。

var s = r'In a raw string, not even \n gets special treatment.';
print(s); // In a raw string, not even \n gets special treatment.

String與Number類型轉(zhuǎn)換

下面是字符串與數(shù)字類型的轉(zhuǎn)換方式:

// String -> int
var one = int.parse('1');
print(one == 1); // true

// String -> double
var onePointOne = double.parse('1.1');
print(onePointOne == 1.1); // true

// int -> String
String oneAsString = 1.toString();
print(oneAsString == '1'); //true

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
print(piAsString == '3.14'); //true

布爾型

Dart 使用 bool 關(guān)鍵字表示布爾類型,布爾類型只有兩個(gè)對(duì)象 truefalse,兩者都是編譯時(shí)常量

Dart的類型安全檢查不允許出現(xiàn)一個(gè)非bool型的判斷,例如if(0) assert(1);

List

Dart使用 bool 關(guān)鍵字表示數(shù)組類型,字面量是由逗號(hào)分隔的一串表達(dá)式或值并以方括號(hào) [] 包裹而組成的:

var lList = [1,2,3]; // 編譯器會(huì)自動(dòng)推斷出數(shù)組的類型List<int>,如果向數(shù)組里添加一個(gè)非int類型,會(huì)報(bào)錯(cuò)

在字面量前面加上關(guān)鍵字 const,會(huì)定義一個(gè)編譯時(shí)常量,那么就不能執(zhí)行賦值操作,如:

var list = const [1,2,3];
list[1] = 0; // 報(bào)錯(cuò)??!

索引

跟其他語(yǔ)言一樣,在Dart里,List的索引也是從0開(kāi)始的,最后一個(gè)元素的索引位置位length-1,可以通過(guò)[]來(lái)獲取對(duì)應(yīng)索引的值。

var list = [1, 2, 3];
print(list.length); // 3
print(list[1]); // 2

list[1] = 1;
print(list[1]); // 1

擴(kuò)展符

Dart提供了 ......?的擴(kuò)展操作,可以將數(shù)組中所有元素插入另一個(gè)數(shù)組內(nèi), 而 ...? 空判斷擴(kuò)展可以避免將null插入到目標(biāo)數(shù)組。

var list = [1, 2, 3];
var list2 = [0, ...list];
print(list2.length); // 4
print(list2); // [0,1,2,3] 

List? list3 = null;
var list4 = [0, ...?list3];
print(list4); // 1

控制語(yǔ)句

Dart 還同時(shí)引入了 集合中的 if 和 集合中的 for 操作,在構(gòu)建集合時(shí),可以使用條件判斷 if和循環(huán) for。

var promoActive = false;
var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];
print(nav); // ['Home', 'Furniture', 'Plants'];

var listOfInts = [1, 2, 3];
var listOfStrings = ['#0', for (var i in listOfInts) '#$i'];
print(listOfStrings[1]); // #1

集合

Dart中使用Set來(lái)表示集合類型,它是一組特定集合的無(wú)序集合??梢酝ㄟ^(guò)字面量{}Set類來(lái)定義

var set = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

Dart 會(huì)根據(jù)字面量來(lái)推斷變量是一個(gè)Set<String>類型,如果往set對(duì)象中添加其他類型的元素,會(huì)拋異常

可以通過(guò)在{}前加上類型來(lái)定義一個(gè)空的集合,或者通過(guò)將{}賦值給一個(gè)Set類型的變量來(lái)實(shí)現(xiàn)。

var set = <String>{};
Set set2 = {};

Map的字面量語(yǔ)法和Set的字面量語(yǔ)法很接近,因?yàn)楝F(xiàn)有Map的字面量語(yǔ)法,因此{(lán)}定義的是一個(gè)Map而不是Set,Dart會(huì)為{}創(chuàng)建一個(gè)Map<dynamic, dynamic>對(duì)象。

常用用法

  • 使用add或者addAll方法向集合中添加元素
  • const定義的常量集合,不能調(diào)用add等方法,否則會(huì)報(bào)錯(cuò)
  • Set支持...擴(kuò)展,支持if/for控制語(yǔ)句
  • 可以通過(guò)length來(lái)獲取集合的數(shù)量

Map

Map 是用來(lái)關(guān)聯(lián) keysvalues 的對(duì)象。其中鍵和值都可以是任何類型的對(duì)象。每個(gè)鍵只能出現(xiàn)一次但是值可以重復(fù)出現(xiàn)多次。 Dart中 Map 提供了 Map 字面量以及 Map 類型兩種形式的 Map

  • 通過(guò)字面量定義Map
    var gifts = {
      // Key:    Value
      'first': 'partridge',
      'second': 'turtledoves',
      'fifth': 'golden rings'
    };
    var nobleGases = {
        2: 'helium',
        10: 'neon',
        18: 'argon',
    };

Dart 將gifts 推斷為Map<String, String>類型,而將nobleGases推斷位Map<int, String>類型,如果向其中添加不正確的類型,則會(huì)拋出異常。

  • 通過(guò)Map類型來(lái)定義Map
    var gifts = Map<String, String>();
    gifts['first'] = 'partridge';
    gifts['second'] = 'turtledoves';
    gifts['fifth'] = 'golden rings';
    var nobleGases = Map<int, String>();
    nobleGases[2] = 'helium';
    nobleGases[10] = 'neon';
    nobleGases[18] = 'argon';

Map的常用用法

  • 給Map添加一組鍵值對(duì),可通過(guò)gifts['third']=glasses;
  • 獲取Map中的值可以使用gifts['forth'];
  • 判斷某個(gè)key是否存在使用gifts['sixth']==null;
  • 使用const定義常量的Map時(shí),不可以添加,修改操作
  • Map同樣支持... 擴(kuò)展操作和if/for控制語(yǔ)句

函數(shù)

Dart是一種真正面向?qū)ο蟮恼Z(yǔ)言,所以即便函數(shù)也是對(duì)象并且類型為 Function,這意味著函數(shù)可以被賦值給變量或者作為其它函數(shù)的參數(shù)。

我們可以像這樣定義一個(gè)函數(shù) :

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

也可以省略 返回類型和參數(shù)類型(不建議這樣做)

 isNoble(atomicNumber) {
   return _nobleGases[atomicNumber] != null;
}

如果函數(shù)內(nèi)只包含一個(gè)表達(dá)式,那么也可以簡(jiǎn)寫(xiě)成:

bool isNoble(int atomicNumber)=> _nobleGases[atomicNumber] != null;

語(yǔ)法 => 表達(dá)式是 { return 表達(dá)式; } 的簡(jiǎn)寫(xiě), => 有時(shí)也稱之為箭頭函數(shù); =>后面只能跟表達(dá)式,不能跟if判斷語(yǔ)句

參數(shù)

函數(shù)的參數(shù)主要分兩種: 必要參數(shù)可選參數(shù)。必要參數(shù)必須定義在參數(shù)列表前面,可選參數(shù)定義在必要參數(shù)的后面??蛇x參數(shù)可以是「命名的」也可以是「位置的」。

命名參數(shù)

命名參數(shù)默認(rèn)時(shí)可選的,除非使用了required關(guān)鍵字標(biāo)記。
命名參數(shù)使用 {param1, param2}來(lái)定義,如果沒(méi)有指定默認(rèn)值,沒(méi)有required標(biāo)記,默認(rèn)值為null

void enableFlags({bool? bold, bool? hidden}){
    ...
}
//使用
enableFlags(bold:true, hidden:false);

可以使用 = 來(lái)給參數(shù)指定默認(rèn)值,指定的默認(rèn)值必須時(shí)一個(gè)常量

void enableFlags({bool bold = false, bool hidden = false}) {...}

// hidden參數(shù)位false
enableFlags(bold: true);

如果希望某個(gè)參數(shù)時(shí)必須要傳的,那么就可以使用required來(lái)修飾,例如:

const Scrollbar({super.key, required Widget child});

如果創(chuàng)建一個(gè)Scrollbar不包含child的時(shí),編譯器就會(huì)報(bào)錯(cuò)

required 參數(shù)也是可以為null的。

位置參數(shù)

使用 [] 將一系列參數(shù)包裹起來(lái),即可將其標(biāo)記為位置參數(shù),因?yàn)樗鼈兊哪J(rèn)值是 null,所以如果沒(méi)有提供默認(rèn)值的話,它們的類型必須得是允許為空 nullable 的類型

String say(String from, String msg, [String? device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}
//不使用位置參數(shù)調(diào)用函數(shù)
print(say('Bob', 'Howdy')); // Bob says Howdy
//使用位置參數(shù)調(diào)用函數(shù)
print(say('Bob', 'Howdy', 'smoke signal')); //Bob says Howdy with a smoke signal

可以使用 = 來(lái)為一個(gè)位置可選參數(shù)指定除了 null 以外的默認(rèn)值。指定的默認(rèn)值必須要為編譯時(shí)的常量

String say(String from, String msg, [String device = 'carrier pigeon']) {
  var result = '$from says $msg with a $device';
  return result;
}

print(say('Bob', 'Howdy'));  //Bob says Howdy with a carrier pigeon

mian()

main() 頂級(jí)函數(shù)作為程序的入口, main() 函數(shù)返回值為 void 并且有一個(gè) List<String> 類型的可選參數(shù)。

函數(shù)是一級(jí)對(duì)象

可以將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)。例如:

void printElement(int element) {
  print(element);
}

var list = [1, 2, 3];

// 將printElement作為一個(gè)參數(shù)
list.forEach(printElement); // 1 2 3

也可以將函數(shù)賦值給一個(gè)變量,比如:

var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
print(loudify('hello')); // !!! HELLO !!!

匿名函數(shù)

顧名思義,就是沒(méi)有名字; 通常稱為 匿名函數(shù)、 Lambda 表達(dá)式Closure 閉包;可以將匿名函數(shù)賦值給一個(gè)變量然后使用。
匿名函數(shù)的定義如下

(param1, params2) {
    ...
}

下面例子就是定義了一個(gè)只有一個(gè)參數(shù)item的匿名函數(shù)用來(lái)打印List中每個(gè)字符串和字符串長(zhǎng)度:

const list = ['apples', 'bananas', 'oranges'];
list.map((item) {
  return item.toUpperCase();
}).forEach((item) {
  print('$item: ${item.length}'); // APPLES: 6 BANANAS: 7 ORANGES: 7
});

運(yùn)算符

下表中是常用的運(yùn)算符,表中從上到下也表示運(yùn)算符的優(yōu)先級(jí)順序。

描述 操作符
一元后綴 expr++ expr-- () [] ?[] . ?. !
一元前綴 -expr !expr ~expr ++expr --expr await expr
乘除運(yùn)算 * / % ~/
加減運(yùn)算 + -
位移 << >> >>>
位運(yùn)算AND &
位運(yùn)算異或 ^
位運(yùn)算或 |
關(guān)系類型判斷 >= > <= < as is is!
相等 == !=
邏輯與 &&
邏輯或
如果空 ??
三元運(yùn)算 expr1 ? expr2 : expr3
級(jí)聯(lián) .. ?..
復(fù)合運(yùn)算 = *= /= += -= &= ^= etc.

類型判斷

|操作符|含義|
|--|--|
|as|類型轉(zhuǎn)換|
|is|如果對(duì)象是指定對(duì)象返回true|
|is!|如果對(duì)象是指定對(duì)象返回false|

當(dāng) obj 實(shí)現(xiàn)了 T 接口時(shí), obj is T 才會(huì)返回 true;
只有當(dāng)obj明確是某個(gè)對(duì)象類型時(shí),才使用as

// 1
(employee as Person).firstName = 'Bob';
// 2
if (employee is Person) {
  // 類型檢查
  employee.firstName = 'Bob';
}

在上面例子中,如果 employeenull 或者不是Person類型時(shí), 注釋1處語(yǔ)句就會(huì)拋出異常,而注釋2處不會(huì)拋出異常。

賦值運(yùn)算

??= 使用場(chǎng)景 obj ??= 123 ,當(dāng)objnull時(shí),才會(huì)賦值 123否則不處理。

條件表達(dá)式

表達(dá)式1 ?? 表達(dá)式2

如果表達(dá)式 1 為非 null 則返回其值,否則執(zhí)行表達(dá)式 2 并返回其值

級(jí)聯(lián)表達(dá)式

級(jí)聯(lián)運(yùn)算符 .., ?.. 可以在同一個(gè)對(duì)象上連續(xù)調(diào)用多個(gè)對(duì)象的變量或方法

var paint = Paint()
  ..color = Colors.black
  ..strokeCap = StrokeCap.round
  ..strokeWidth = 5.0;

等同于代碼:

var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;

如果對(duì)象可能為null的話,可以使用?..

querySelector('#confirm') 
  ?..text = 'Confirm' 
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

代碼等同于

var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();

級(jí)聯(lián)對(duì)象可以嵌套使用:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

在調(diào)用返回對(duì)象的函數(shù)時(shí),一定要謹(jǐn)慎使用級(jí)聯(lián)操作;如果函數(shù)返回void,那么就不能使用級(jí)聯(lián)操作。

其他運(yùn)算符

操作符 含義
?[] 判空訪問(wèn)List,不為空時(shí)訪問(wèn)List中元素
?. 條件訪問(wèn)成員,不為空時(shí)訪問(wèn)成員
斷言操作,認(rèn)為一定不為空訪問(wèn)相關(guān)成員,如果為空拋出異常

控制語(yǔ)句

if-else

與其他語(yǔ)言類似,通過(guò)條件判斷執(zhí)行代碼塊 其中 elseelse if 是可選判斷。但是判斷的條件一定是bool型,不可以是其他類型。

if(表達(dá)式1){
...
}else if(表達(dá)式2){
...
}else{
...
}

for循環(huán)

  • 可以使用標(biāo)準(zhǔn)的for循環(huán)進(jìn)行迭代
    for(int i=0; i<10; i++)
  • 使用for-in方法遍歷一個(gè)可迭代的對(duì)象
    for(final a in objs)
  • 使用可迭代對(duì)象的forEach方法
    iteractor.forEach()

while 和 do-while循環(huán)

whiledo-while的區(qū)別是:

  • while會(huì)先進(jìn)行判斷,然后再執(zhí)行代碼塊,
  • do-while是先執(zhí)行代碼塊,再進(jìn)行判斷

contin 和 break

continue 表示跳過(guò)此次循環(huán),break表示跳出循環(huán)

如果在Iterable對(duì)象中,可以使用where代替continue

candidates
    .where((c) => c.yearsExperience >= 5)
    .forEach((c) => c.interview());

switch-case

Switch 語(yǔ)句在Dart中使用 == 來(lái)比較整數(shù)、字符串或編譯時(shí)常量,比較的兩個(gè)對(duì)象必須是同一個(gè)類型且不能是子類并且沒(méi)有重寫(xiě) == 操作符。 枚舉類型非常適合在 Switch 語(yǔ)句中使用。

非空case想要實(shí)現(xiàn)穿透可通過(guò)continue來(lái)實(shí)現(xiàn):

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;

  nowClosed:
  case 'NOW_CLOSED':
    executeNowClosed();
    break;
}

每個(gè)case內(nèi)都可以有局部變量,并且只在當(dāng)前case可見(jiàn)。

注釋

單行注釋

單行注釋以//開(kāi)始,所在行的內(nèi)容都屬于注釋內(nèi)容

// 這是一個(gè)單行注釋

多行注釋

多行注釋以/*開(kāi)頭,以*/結(jié)尾,在/**/之間的內(nèi)容都會(huì)被編譯器忽略,認(rèn)為是注釋內(nèi)容

/*
這是一個(gè)多行注釋
注釋第二行內(nèi)容
...
*/
/*
嵌套注釋的外層
  /*
    嵌套注釋內(nèi)層
  */
嵌套注釋外層
*/

文檔注釋

文檔注釋使用/// 或者是/**,多個(gè)連續(xù)///注釋與多行注釋效果一致。多行文檔注釋,編譯器會(huì)忽略注釋的內(nèi)容,但是如果使用了[],則編譯器會(huì)產(chǎn)生引用括號(hào)內(nèi)的內(nèi)容如類、方法、字段、頂級(jí)變量、函數(shù)和參數(shù)。

///這是一個(gè)文檔注釋舉例
///如果使用了中括號(hào),則會(huì)解析括號(hào)內(nèi)容,引用相關(guān)內(nèi)容[feed]

上面舉例中[feed]將會(huì)生成一個(gè)鏈接,指向feed的方法文檔

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容