Flutter基礎(chǔ)篇(2)-- 老司機(jī)用一篇博客帶你快速熟悉Dart語(yǔ)法

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。http://www.itdecent.cn/p/3d927a7bf020

轉(zhuǎn)載請(qǐng)標(biāo)明出處:
http://www.itdecent.cn/p/3d927a7bf020
本文出自 AWeiLoveAndroid的博客


Flutter系列博文鏈接 ↓:

工具安裝:

Flutter基礎(chǔ)篇:

Flutter進(jìn)階篇:

Dart語(yǔ)法系列博文鏈接 ↓:

Dart語(yǔ)法基礎(chǔ)篇:

Dart語(yǔ)法進(jìn)階篇:


【前言】Dart語(yǔ)言是使用flutter框架開發(fā)時(shí)候必備的語(yǔ)言,flutter是一個(gè)跨平臺(tái)的框架,一套代碼就可以完美實(shí)現(xiàn)安卓和ios兩個(gè)平臺(tái),適配也很不錯(cuò),Dart語(yǔ)言很友好,和java很類似,學(xué)習(xí)成本也是很低的。所以這也是我推薦學(xué)習(xí)Dart語(yǔ)言的一個(gè)原因。

從本篇文章開始講解Dart語(yǔ)言的基本使用,我將會(huì)連續(xù)推出好幾篇文章詳解,希望幫助大家快速掌握Dart語(yǔ)言。


本文目錄:

一、注釋
二、關(guān)鍵字(56個(gè))
三、變量和常量
四、特殊數(shù)據(jù)類型
五、運(yùn)算符
六、控制流程語(yǔ)句
七、異常


本文代碼同步發(fā)布在Github:
https://github.com/AweiLoveAndroid/Flutter-learning/tree/master/projects/dart_demo

怎么運(yùn)行代碼?

如果你使用IDEA或者Android Studio:

打開IDEA或者Android Studio,新建一個(gè)Flutter項(xiàng)目,然后在test目錄運(yùn)行我的代碼;或者里面去寫你自己的dart文件,然后右鍵run就可以運(yùn)行了。(注意:需要連接手機(jī)或者模擬器)。

如果你使用vscode:

打開vscode,執(zhí)行菜單欄運(yùn)行,就可以了(確保只有一個(gè)dart文件,免得運(yùn)行的文件不是你想要的,就很尷尬了,vscode也可以設(shè)置默認(rèn)運(yùn)行的文件是哪個(gè),但是新手不建議去設(shè)置,很麻煩。因?yàn)槟銈兿胱羁斓倪\(yùn)行效果,所有建議只有一個(gè)dart文件是最好的)。


一、注釋

Dart的注釋分為3種:?jiǎn)涡凶⑨?、多行注釋、文檔注釋。

1、單行注釋以//開頭。Dart編譯器會(huì)忽略//和行尾之間的所有內(nèi)容。

例如:// todo:待完成

2、多行注釋以/*開頭,以*/結(jié)尾。介于/**/兩者之間的內(nèi)容會(huì)被編譯器忽略(除非該注釋是一個(gè)文檔注釋)。多行注釋可以嵌套。

例如:/* todo:待完成 */

3、文檔注釋以///或者/**開頭。可以通過(guò)dartdoc命令導(dǎo)出文檔。

文檔注釋的使用,例如:/// todo:待完成

文檔的導(dǎo)出如圖所示:


文檔的導(dǎo)出

導(dǎo)出的結(jié)果在我的工程根路徑的/doc/api/文件夾里面,如圖所示:

導(dǎo)出的結(jié)果

然后瀏覽器打開index.html就可以看到文檔了。如圖所示:

本地的文檔

二、關(guān)鍵字(60個(gè))

5個(gè)上下文關(guān)鍵字(僅在特定位置具有含義。它們?cè)谌魏蔚胤蕉际怯行У臉?biāo)識(shí)符)

關(guān)鍵字 - - -
async hide on show
sync - - -

其中內(nèi)置標(biāo)志符有:(20個(gè))

關(guān)鍵字 - - -
abstract as covariant defered
dynamic export external factory
Function get implements import
interface library mixin operator
part set static typedef

Dart新增的,有限的保留字,支持異步功能的關(guān)鍵字有:(2個(gè))

關(guān)鍵字 - - -
await yield

33個(gè)保留字(不能使用保留字作為標(biāo)識(shí)符)

關(guān)鍵字 - - -
assert break case catch
class const continue default
do else enum extends
false final finally for
if in is new
null rethrow return super
switch this throw true
try var void while
with - - -

跟java相比,Dart特有的關(guān)鍵字有:(27個(gè))

關(guān)鍵字 - - -
as async await covariant
deferred dynamic export external
factory Function get hide
in is library mixin
on operator part rethrow
set show sync typedef
var with yield

三、變量和常量

(一)變量的聲明,可以使用 var、Object 或 dynamic 關(guān)鍵字。

創(chuàng)建變量并初始化變量實(shí)例:

var name = '張三' ;

變量存儲(chǔ)引用。

    1. 使用Object或dynamic關(guān)鍵字
dynamic name = '張三';

調(diào)用的變量name包含對(duì)String值為“張三” 的對(duì)象的引用。
name推斷變量的類型是String,但可以通過(guò)指定它來(lái)更改該類型。
如果對(duì)象不限于單一類型(沒(méi)有明確的類型),請(qǐng)使用Object或dynamic關(guān)鍵字

Object name = '張三';
dynamic name = '李四';
    1. 顯式聲明將被推斷的類型

比如String,int等。

//可以使用String顯示聲明字符串類型
String name = '張三' ; //代替var name = '張三';

這個(gè)類型有很多,具體在下文有介紹。

(二)默認(rèn)值

未初始化的變量的初始值為null(包括數(shù)字),因此數(shù)字、字符串都可以調(diào)用各種方法。

//測(cè)試 數(shù)字類型的初始值是什么?
int intDefaultValue;
// assert 是語(yǔ)言內(nèi)置的斷言函數(shù),僅在檢查模式下有效
// 在開發(fā)過(guò)程中, 除非條件為真,否則會(huì)引發(fā)異常。(斷言失敗則程序立刻終止)
assert(intDefaultValue == null);
print(intDefaultValue);//打印結(jié)果為null,證明數(shù)字類型初始化值是null

(三)Final 和 Const的用法

如果您從未打算更改一個(gè)變量,那么使用 final 或 const,不是var,也不是一個(gè)類型。
一個(gè) final 變量只能被設(shè)置一次;const 變量是一個(gè)編譯時(shí)常量。(Const變量是隱式的final。)
final的頂級(jí)或類變量在第一次使用時(shí)被初始化。

  • 1、被final或者const修飾的變量,變量類型可以省略。
//可以省略String這個(gè)類型聲明
final name1 = "張三";
//final String name1  = "張三";
    
const name2 = "李四";
//const String name2 = "李四";
  • 2、被 final 或 const 修飾的變量無(wú)法再去修改其值。
final name1 = "張三";
// 這樣寫,編譯器提示:a final variable, can only be set once
// 一個(gè)final變量,只能被設(shè)置一次。
//name1 = "zhangsan";
    
const name2 = "李四";

// 這樣寫,編譯器提示:Constant variables can't be assigned a value
// const常量不能賦值
// name2 = "lisi";
  • 3、注意:flnal 或者 const 不能和 var 同時(shí)使用
//這樣寫都會(huì)報(bào)錯(cuò)
//final var name1 = "張三";
//const var name2 = "李四";
  • 4、常量如果是類級(jí)別的,請(qǐng)使用 static const
static const speed = 100;
  • 5、常量的運(yùn)算
const speed = 100; //速度(km/h)
const double distance = 2.5 * speed; // 距離 = 速度 * 時(shí)間

final speed2 = 100; //速度(km/h)
final double distance2 = 2.5 * speed2; // 距離 = 速度 * 時(shí)間
  • 6、const關(guān)鍵字不只是聲明常數(shù)變量。您也可以使用它來(lái)創(chuàng)建常量值,以及聲明創(chuàng)建常量值的構(gòu)造函數(shù)。 任何變量都可以有一個(gè)常量值。
// 注意: [] 創(chuàng)建的是一個(gè)空的list集合
// const []創(chuàng)建一個(gè)空的、不可變的列表(EIL)。
var varList = const []; // varList 當(dāng)前是一個(gè)EIL
final finalList = const []; // finalList一直是EIL
const constList = const []; // constList 是一個(gè)編譯時(shí)常量的EIL

// 可以更改非final,非const變量的值
// 即使它曾經(jīng)具有const值
varList = ["haha"];

// 不能更改final變量或const變量的值
// 這樣寫,編譯器提示:a final variable, can only be set once
// finalList = ["haha"];
// 這樣寫,編譯器提示:Constant variables can't be assigned a value  
// constList = ["haha"];
  • 7、只要任何插值表達(dá)式是一個(gè)計(jì)算結(jié)果為null或數(shù)字,字符串或布爾值的編譯時(shí)常量,那么文字字符串就是編譯時(shí)常量。(關(guān)于$表達(dá)式和不同的數(shù)據(jù)類型后面會(huì)講解。)
// 這些是常量字符串
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// 這些不是常量字符串

var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = const [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString';

//這樣用就會(huì)報(bào)錯(cuò):Const variables must be initialized with a constant value
// const常量必須用conat類型的值初始化。
// const invalidConstString = '$aNum $aBool $aString $aConstList';

四、特殊數(shù)據(jù)類型

Dart支持以下特殊類型:

numbers 數(shù)字
strings 字符串
booleans 布爾
lists list集合(也稱為數(shù)組)
maps map集合
runes 字符(用于在字符串中表示Unicode字符)

(一)num數(shù)字類型

num是數(shù)字類型的父類,有兩個(gè)子類 intdouble。
num類型包括基本的運(yùn)算符,如+,-,/和*,位運(yùn)算符,如>>,在int類中定義。如果num和它的子類沒(méi)有你要找的東西,math庫(kù)可能會(huì)找到。比如你會(huì)發(fā)現(xiàn)abs(),ceil()和floor()等方法。

(1)int類型

int表示整數(shù),int默認(rèn)是64位二進(jìn)制補(bǔ)碼整數(shù),int的取值不大于64位,具體取決于平臺(tái)。編譯為JavaScript時(shí),整數(shù)僅限于valus,可以用雙精度浮點(diǎn)值精確表示。可用的整數(shù)值包括-253和253之間的所有整數(shù),以及一些幅度較大的整數(shù)。這包括一些大于2^63的整數(shù)。 因此,在編譯為JavaScript的Dart VM和Dart代碼之間,int類中的運(yùn)算符和方法的行為有時(shí)會(huì)有所不同。例如,當(dāng)編譯為JavaScript時(shí),按位運(yùn)算符將其操作數(shù)截?cái)酁?2位整數(shù)。
示例如下:

int intNum1 = 10 ;
print(intNum1);//結(jié)果是10
int intNum2 = 0xDEADBEEF ;
print(intNum2);//結(jié)果是3735928559

判斷一個(gè)int值需要多少bit(位),可以使用bitLength,例如:

// bitLength 返回存儲(chǔ)此int整數(shù)所需的最小位數(shù)
int a1 = 1; // 占了1個(gè)bit     相當(dāng)于二進(jìn)制數(shù)字 00000000 00000001
int a2 = 12; // 占了4個(gè)bit    相當(dāng)于二進(jìn)制數(shù)字 00000000 00001100
int a3 = 123; // 占了7個(gè)bit   相當(dāng)于二進(jìn)制數(shù)字 00000000 01111011
int a4 = 1234; // 占了11個(gè)bit 相當(dāng)于二進(jìn)制數(shù)字 00000100 11010010
print('${a1.bitLength}'); //  1
print('${a2.bitLength}');  // 4
print('${a3.bitLength}'); // 7
print('${a4.bitLength}'); // 11
(2)double類型

Dart的double是IEEE 754標(biāo)準(zhǔn)中規(guī)定的64位浮點(diǎn)數(shù)。double的最大值是:1.7976931348623157e+308,double類里面有一個(gè)常量maxFinite,我們通過(guò)語(yǔ)句print(double. maxFinite)可以得到double的最大值。
如果一個(gè)數(shù)字包含一個(gè)小數(shù),那么它就是一個(gè)double類型。示例如下:

double doubleNum1 = 1.1;
print(doubleNum1); //結(jié)果是1.1
double doubleNum2 = 1.42e5;
print(doubleNum2); //結(jié)果是142000.0
(3)Dart2.1里面新增特性,當(dāng)double的值為int值時(shí),int自動(dòng)轉(zhuǎn)成double。

例如:double test = 12;//打印結(jié)果是12.0

(4)Dart2.1,int也有api轉(zhuǎn)成double。

例如:

int test = 10;
print(test.toDouble()); // 結(jié)果是: 10.0
(5)Dart2.1,double也有api轉(zhuǎn)成int,會(huì)把小數(shù)點(diǎn)后面的全部去掉。

例如:

double test2 = 15.1;
double test3 = 15.1234;
print(test2.toInt());// 結(jié)果是15
print(test3.toInt());// 結(jié)果是15

(二)String字符串類型

Dart里面的String是一系列 UTF-16代碼單元。

(1)您可以使用單引號(hào)或雙引號(hào)來(lái)創(chuàng)建一個(gè)字符串。
String str1 = '單引號(hào)基本使用demo.';
String str2 = "雙引號(hào)基本使用demo.";
(2)單引號(hào)或者雙引號(hào)里面嵌套使用引號(hào)。

單引號(hào)里面嵌套單引號(hào),或者//雙引號(hào)里面嵌套雙引號(hào),必須在前面加反斜杠。

// 單引號(hào)里面有單引號(hào),必須在前面加反斜杠
String str3 = '單引號(hào)里面有單引號(hào)it\'s,必須在前面加反斜杠.';
//雙引號(hào)里面嵌套單引號(hào)(正常使用)
String str4 = "雙引號(hào)里面有單引號(hào)it's.";
//單引號(hào)里面嵌套雙引號(hào)(正常使用)
String str5 = '單引號(hào)里面有雙引號(hào),"hello world"';
//雙引號(hào)里面嵌套雙引號(hào),必須在前面加反斜杠
String str6 = "雙引號(hào)里面有雙引號(hào),\"hello world\"";

print(str3);// 雙引號(hào)里面有單引號(hào)it's,必須在前面加反斜杠
print(str4);// 雙引號(hào)里面有單引號(hào)it's.
print(str5);// 單引號(hào)里面有雙引號(hào),hello world"
print(str6);//雙引號(hào)里面有雙引號(hào),"hello world"
(3)多個(gè)字符串相鄰中間的空格問(wèn)題:

除了單引號(hào)嵌套單引號(hào)或者雙引號(hào)嵌套雙引號(hào)不允許出現(xiàn)空串之外,其余的幾種情況都是可以運(yùn)行的。
示例如下:

這個(gè)會(huì)報(bào)錯(cuò)
//String blankStr1 = 'hello''''world';
//這兩個(gè)運(yùn)行正常
String blankStr2 = 'hello'' ''world'; //結(jié)果: hello world
String blankStr3 = 'hello''_''world'; //結(jié)果: hello_world


// 這個(gè)會(huì)報(bào)錯(cuò)
//String blankStr4 = "hello""""world";
這兩個(gè)運(yùn)行正常
String blankStr5 = "hello"" ""world"; //結(jié)果: hello world
String blankStr6 = "hello""_""world"; //結(jié)果: hello_world

單引號(hào)里面有雙引號(hào),混合使用運(yùn)行正常

String blankStr7 = 'hello""""world'; //結(jié)果: hello""""world
String blankStr8 = 'hello"" ""world'; //結(jié)果: hello"" ""world
String blankStr9 = 'hello""_""world'; //結(jié)果: hello""_""world

雙引號(hào)里面有單引號(hào),混合使用運(yùn)行正常

String blankStr10 = "hello''''world"; //結(jié)果: hello''''world
String blankStr11 = "hello'' ''world"; //結(jié)果: hello'' ''world
String blankStr12 = "hello''_''world"; //結(jié)果: hello''_''world
(4)您可以使用相鄰字符串文字或+ 運(yùn)算符連接字符串:
  1. 直接把相鄰字符串寫在一起,就可以連接字符串了。
  String connectionStr1 =  '字符串連接''甚至可以在''換行的時(shí)候進(jìn)行。';
  print(connectionStr1);// 字符串連接甚至可以在換行的時(shí)候進(jìn)行。
  1. 用+把相鄰字符串連接起來(lái)。
  String connectionStr2 =  '字符串連接'+ '甚至可以在'+ '換行的時(shí)候進(jìn)行。';
  print(connectionStr2);// 字符串連接甚至可以在換行的時(shí)候進(jìn)行。
  1. 使用單引號(hào)或雙引號(hào)的三引號(hào):
String connectionStr3 = ''' 
  這是用單引號(hào)創(chuàng)建的
  多行字符串。
  ''' ;
print(connectionStr3);
String connectionStr4 = """這是用雙引號(hào)創(chuàng)建的
  多行字符串。""";
print(connectionStr4);

print(connectionStr3)輸出結(jié)果如下:

  這是用單引號(hào)創(chuàng)建的
  多行字符串。

print(connectionStr4)的輸出結(jié)果如下:

這是用雙引號(hào)創(chuàng)建的
  多行字符串。
(5)關(guān)于轉(zhuǎn)義符號(hào)的使用

聲明raw字符串(前綴為r),在字符串前加字符r,或者在\前面再加一個(gè)\
可以避免“\”的轉(zhuǎn)義作用,在正則表達(dá)式里特別有用。

舉例如下:

print(r"換行符:\n"); //這個(gè)結(jié)果是 換行符:\n
print("換行符:\\n"); //這個(gè)結(jié)果是 換行符:\n
print("換行符:\n");  //這個(gè)結(jié)果是 換行符:
(6)使用$可以獲得字符串中的內(nèi)容,使用${表達(dá)式}也可以將表達(dá)式的值放入字符串中。使用${表達(dá)式}時(shí)可以使用字符串拼接,也可以使用String類或者Object里面的某些方法獲得相關(guān)字符串屬性。

1、使用$+字符串

var height = 48.0;
print('當(dāng)前標(biāo)題的高度是$height'); //當(dāng)前標(biāo)題的高度是48.0

2、使用$+字符串,以及字符串拼接

String name = "張三";
print("$name"+"是我們的部門經(jīng)理"); // 張三是我們的部門經(jīng)理

3、這里使用了字符串的拼接,以及使用了String類里面的toUpperCase()函數(shù),把字母全部變成大寫。

String replaceStr = 'Android Studio';
assert('你知道' +
'${replaceStr.toUpperCase()}'
+ '最新版本是多少嗎?' ==
'你知道ANDROID STUDIO最新版本是多少嗎?'); 

注:==操作符測(cè)試兩個(gè)對(duì)象是否相等。assert是斷言,如果條件為true,繼續(xù)進(jìn)行,否則拋出異常,中端操作。

(三)bool布爾類型

Dart表示布爾值的類型叫做bool,它有兩個(gè)值,分別是:truefalse,它們都是編譯時(shí)常量。
Dart使用的是顯式的檢查值,檢查值的類型,如下所示:

  // 檢查是否為空字符串
  var emptyStr = '';
  assert(emptyStr.isEmpty);

  // 檢查是否小于等于0
  var numberStr = 0;
  assert(numberStr <= 0);  

  // 檢查是否為null
  var nullStr;
  assert(nullStr == null);

  // 檢查是否為NaN
  var value = 0 / 0;
  assert(value.isNaN);

assert 是Dart語(yǔ)言里的的斷言函數(shù),僅在Debug模式下有效。
在開發(fā)過(guò)程中, 除非條件為真,否則會(huì)引發(fā)異常。(斷言失敗則程序立刻終止)。

(四)list集合,也成為數(shù)組

在Dart中,數(shù)組是List對(duì)象,因此大多數(shù)人只是將它們稱為L(zhǎng)ist。
以下是一個(gè)簡(jiǎn)單的Dart的List:

創(chuàng)建一個(gè)int類型的list

List list = [10, 7, 23];
print(list);// 輸出結(jié)果  [10, 7, 23]

要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量const的list,示例如下:

List constantList = const[10,3,15];
print(constantList);// 輸出結(jié)果  [10, 3, 15]

注意事項(xiàng):

1.可以直接打印list包括list的元素,list也是一個(gè)對(duì)象。但是java必須遍歷才能打印list,java若直接打印list,結(jié)果是地址值。
2.和java一樣list里面的元素必須保持類型一致,不一致就會(huì)報(bào)錯(cuò)。
3.和java一樣list的角標(biāo)從0開始。

Dart的list集合給我們提供了很多api,示例如下,api太多就不逐個(gè)展示了:

操作 代碼 含義 輸出結(jié)果
新增 list.add(1);print(list); 把數(shù)字1添加到list中,默認(rèn)是添加到末尾 [10, 7, 23, 1]
移除 list.remove(1);print(list); 移除數(shù)字1 [10, 7, 23]
插入 list.insert(0, 5);print(list); 在索引為0的地方插入數(shù)字5 [5, 10, 7, 23]
查找某個(gè)索引的值 int value = list.indexOf(10);print(value); 查找10在list中的索引 1
判斷元素是否包含 bool result = list.contains(5);print(result); 查找list中是否包含數(shù)字5 true

(五)map集合

Dart中的map是將鍵和值相關(guān)聯(lián)的對(duì)象。鍵和值都可以是任何類型的對(duì)象。每個(gè)鍵只出現(xiàn)一次,但您可以多次使用相同的值。

(1)創(chuàng)建方式:
    1. 直接聲明,用{}表示,里面寫key和value,每組鍵值對(duì)中間用逗號(hào)隔開。
Map companys = {'first': '阿里巴巴', 'second': '騰訊', 'fifth': '百度'};
print(companys);//打印結(jié)果 {first: 阿里巴巴, second: 騰訊, fifth: 百度}
    1. 先聲明,再去賦值。
  Map companys1 = new Map();
  companys1['first'] = '阿里巴巴';
  companys1['second'] = '騰訊';
  companys1['fifth'] = '百度';
  print(companys1);
  //打印結(jié)果 {first: 阿里巴巴, second: 騰訊, fifth: 百度}
    1. 要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量const的map,請(qǐng)?jiān)趍ap文字之前添加const:
final fruitConstantMap = const {2: 'apple',10: 'orange',18: 'banana'};
// 打印結(jié)果{second: 騰訊, fifth: 百度, 5: 華為}
(2)添加元素。格式: 變量名[key] = value,其中key可以是不同類型。
//添加一個(gè)新的元素,key為“5”,value為“華為”
  companys[5] = '華為';
  print(companys);//打印結(jié)果 {first: 阿里巴巴, second: 騰訊, fifth: 百度, 5: 華為}
(3)修改元素。格式:變量名[key] = value

例如:把key為first的元素對(duì)應(yīng)的value改成 alibaba

  companys['first'] = 'alibaba';
  print(companys);//打印結(jié)果 {first: alibaba, second: 騰訊, fifth: 百度, 5: 華為}
(4)查詢?cè)?/h5>
  bool mapKey = companys.containsKey('second');
  bool mapValue = companys.containsValue('百度');
  print(mapKey); //結(jié)果為:true
  print(mapValue); //結(jié)果為:true
(5)刪除元素.可以使用map的remove或者clear方法。
  companys.remove('first');// 移除key為“first”的元素。
  print(companys);// 打印結(jié)果{second: 騰訊, fifth: 百度, 5: 華為}

  companys.clear();// 清空map集合的數(shù)據(jù)。
  print(companys);// 打印結(jié)果{}
(6)關(guān)于map集合的小結(jié):
1.創(chuàng)建map有兩種方式。
2.map的key類型不一致也不會(huì)報(bào)錯(cuò)。
3.添加元素的時(shí)候,會(huì)按照你添加元素的順序逐個(gè)加入到map里面,哪怕你的key不連續(xù)。
比如key分別是 1,2,4,看起來(lái)有間隔,事實(shí)上添加到map的時(shí)候{1:value,2:value,4:value} 這種形式。
4.添加的元素的key如果是map里面某個(gè)key的英文,照樣可以添加到map里面,
比如可以為3和key為three可以同時(shí)存在。
5.map里面的key不能相同,但是value可以相同,value可以為空字符串或者為null。

(六)runes 字符(用于在字符串中表示Unicode字符)

Unicode為世界上所有的書寫系統(tǒng)中使用的每個(gè)字母,數(shù)字和符號(hào)定義了唯一的數(shù)值。
Dart字符串是UTF-16代碼單元的序列,所以在字符串中表達(dá)32位Unicode值需要特殊的語(yǔ)法。
Unicode代碼點(diǎn)的常用方法是\uXXXX,其中XXXX是一個(gè)4位十六進(jìn)制值。

例如,心形字符()是\u2665。要指定多于或少于4個(gè)十六進(jìn)制數(shù)字,請(qǐng)將該值放在大括號(hào)中。 例如,笑的表情符號(hào)是\u{1f600}。

String類有幾個(gè)屬性可以用來(lái)提取符文信息。 codeUnitAt和codeUnit屬性返回16位代碼單元。
以下示例說(shuō)明了符文,16位代碼單元和32位代碼點(diǎn)之間的關(guān)系。

var clapping = '\u{1f44f}';
print(clapping);
print(clapping.codeUnits);
print(clapping.runes.toList());

//使用String. fromCharCodes顯示字符圖形 
Runes input = new Runes(
        '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
print(new String.fromCharCodes(input));

五、運(yùn)算符

運(yùn)算符在每一種語(yǔ)言中都很常見,Dart的運(yùn)算符如下表所示:

我這里不詳細(xì)去講解每個(gè)運(yùn)算符的用法,我這里主要講一下Dart里面比較有代表性的以及有特點(diǎn)的一些運(yùn)算符相關(guān)用法。

(一)?..一樣,但最左邊的操作數(shù)可以為空。

比如:Test?.funs從表達(dá)式Test中選擇屬性funs,除非Test為空(當(dāng)Test為空時(shí),Test?.funs的值為空)。

class Test {
  static int funs = 5;

  Test() {
    print('構(gòu)造函數(shù) Test');
  }
  static fun() {
    print('Test fun函數(shù)');
  }
}
void main(){
  print(Test?.funs); // 打印5
}

(二)..級(jí)聯(lián)符號(hào)..

級(jí)聯(lián)符號(hào)..允許您在同一個(gè)對(duì)象上進(jìn)行一系列操作。 除了函數(shù)調(diào)用之外,還可以訪問(wèn)同一對(duì)象上的字段。其實(shí)相當(dāng)于java的鏈?zhǔn)秸{(diào)用。
例如:

String s = (new StringBuffer()
        ..write('test1 ')
        ..write('test2 ')
        ..write('test3 ')
        ..write('test4 ')
        ..write('test5'))
      .toString();
print(s); // test1 test2 test3 test4 test5

(三)?? 三目運(yùn)算符的一種形式。

expr1 ?? expr2 表示如果expr1非空,則返回其值; 否則返回expr2的值。

//普通三元運(yùn)算符
int a = 10;
var values = a > 5 ? a : 0;
//??操作符
print('a ??=3 : ${a ??= 3}');  // 3

(四)~/ 除法,返回一個(gè)整數(shù)結(jié)果,其實(shí)就是取商。

小學(xué)都學(xué)過(guò):被除數(shù) ÷ 除數(shù) = 商 ... 余數(shù),在Dart里面A ~/ B = C,這個(gè)C就是商,這個(gè)語(yǔ)句相當(dāng)于Java里面的A / B = C。Dart與java不同的是,Dart里面如果使用A / B = D語(yǔ)句,這個(gè)結(jié)果計(jì)算出來(lái)的是真實(shí)的結(jié)果。示例如下:

  var result1 = 15/7;
  print(result1); // 結(jié)果是:2.142857...
  var result2 = 15~/7;
  print(result2); // 結(jié)果是:2

順便提一下取模操作,在Dart里面A % B = E,這個(gè)E就是余數(shù),%符號(hào)表示取模,例如:

 var result3 = 15%7;
  print(result3); // 結(jié)果是:1

(五)as、is與is!

as 判斷屬于某種類型
is 如果對(duì)象具有指定的類型,則為true
is! 如果對(duì)象具有指定的類型,則為false

例如:

class Test {
  static int funs = 5;

  Test() {
    print('構(gòu)造函數(shù) Test');
  }
  static fun() {
    print('Test fun函數(shù)');
  }
}

class Test2 extends Test {
  Test2() {
    print('構(gòu)造函數(shù) Test2');
  }
  void fun() {
    print('Test2 fun函數(shù)');
  }
}

void main(){
  print(test2 is Test);  // true
  print(test is! Test2);  // true

  (test2 as Test2).fun();  // Test2 fun函數(shù)
  // 相當(dāng)于
  // if (test2 is Test) {
  //   test2.fun();
  // }

六、控制流程語(yǔ)句

控制流程語(yǔ)句和Java語(yǔ)言差不多,有這些語(yǔ)句:

(一)if else

if(條件語(yǔ)句){
    內(nèi)容體
}else{
內(nèi)容體
}

(二)for循環(huán)

1.簡(jiǎn)單for循環(huán)

for(初始值;判斷條件;循環(huán)后的語(yǔ)句){
    內(nèi)容體
}

例如:

for(int i=0;i<10;i++){
    print(i);
}

也可以通過(guò)for循環(huán)內(nèi)部的閉包獲取索引的值。

var array = [];
for(var i=0;i<10;i++){
    array.add(()=> print(i));
}

2.使用foreach循環(huán),一般List和Set都可以使用foreach遍歷元素。

如果要迭代的對(duì)象是Iterable,或者你不想知道當(dāng)前的迭代次數(shù),可以使用foreach()方法。

var numbers = [1,2,3,4,5,6,7,8,9];
numbers.foreach((number)=> print(number));

3.使用for in循環(huán),一般List和Set使用for-in遍歷元素。

var list = [1,2,3];
for(var data in list){
    print(data);
}

4.Dart的for循環(huán)里面可以使用標(biāo)記:(比較有特色的地方)

Dart的標(biāo)記:標(biāo)記是后面跟著冒號(hào)的標(biāo)識(shí)符。帶標(biāo)記的陳述是以標(biāo)記 L為前綴的陳述。帶標(biāo)簽的case子句是標(biāo)簽L前綴的switch語(yǔ)句中的case子句。標(biāo)簽的唯一作用是為“break”和“continue”聲明提供對(duì)象。
大多數(shù)此功能與其他語(yǔ)言類似,因此以下大部分內(nèi)容可能對(duì)讀者來(lái)說(shuō)都很熟悉。Dart的switch聲明中處理continue是比較獨(dú)特的,所以這一部分需要一點(diǎn)時(shí)間去閱讀和熟悉。

  • 1.循環(huán)(Loops)

標(biāo)簽最常用作breakcontinue內(nèi)部循環(huán)。假設(shè)你有嵌套的循環(huán),并要跳轉(zhuǎn)到breakcontinue到外部循環(huán)。如果沒(méi)有標(biāo)記,這不可能(輕松)實(shí)現(xiàn)。

以下示例使用continue 標(biāo)記名稱從內(nèi)部循環(huán)直接跳轉(zhuǎn)到外部循環(huán)的下一輪循環(huán):

// 返回具有最小總和的內(nèi)部列表(正整數(shù))。
/// Returns the inner list (of positive integers) with the smallest sum.
List<int> smallestSumList(List<List<int>> lists) {
  var smallestSum = 0xFFFFFFFF; //已知list的總和較小。
  var smallestList = null;
  outer: // 這就是標(biāo)記
  for (var innerList in lists) {
    var sum = 0;
    for (var element in innerList) {
      assert(element >= 0);
      sum += element;
      // 無(wú)需繼續(xù)迭代內(nèi)部列表。它的總和已經(jīng)太高了。
      if (sum > smallestSum) continue outer; // continue 跳出到標(biāo)記處(outer)
    }
    smallestSum = sum;
    smallestList = innerList;
  }
  return smallestList;
}

此函數(shù)在所有l(wèi)ist中運(yùn)行,但只要總和過(guò)高,就會(huì)停止累加變量。

同理,可以使用break跳出到外部循環(huán):

// 計(jì)算第一個(gè)非空l(shuí)ist
List<int> firstListWithNullValueList(List<List<int>> lists) {
  var firstListWithNullValues = null;
  outer:
  for (var innerList in lists) {
    for (var element in innerList) {
      if (element == null) {
        firstListWithNullValues = innerList;
        break outer;  // break 返回到標(biāo)記處
      }
    }
  }
  // 現(xiàn)在繼續(xù)正常的工作流程
  if (firstListWithNullValues != null) {
    // ...
  }
  return firstListWithNullValues;
}
  • 2.跳出代碼塊

標(biāo)記也可以用于跳出代碼塊。假設(shè)我們想要統(tǒng)一處理錯(cuò)誤條件,但有多個(gè)條件(可能是深度嵌套)來(lái)揭示(reveal)錯(cuò)誤。標(biāo)簽可以幫助構(gòu)建此代碼。

void doSomethingWithA(A a) {
  errorChecks: {
    if (a.hasEntries) {
      for (var entry in a.entries) {
        if (entry is Bad) break errorChecks;   // 跳出代碼塊
      }
    }
    if (a.hasB) {
      var b = new A.b();
      if (b.inSomeBadState()) break errorChecks;  // 跳出代碼塊
    }
    // 一些看起來(lái)都正常
    use(a);
    return;
  }
  // 錯(cuò)誤的情況,執(zhí)行這里的代碼:
  print("something bad happened");
}

class A{
  bool hasEntries = false;
  bool hasB = true;
  List<Bad> entries = [new Bad2(),new Bad2()];
  A.b(){

  }

  bool inSomeBadState(){
    return false;
  }
  
}

void use(A a){}

abstract class Bad{}
class Bad1 extends Bad{}
class Bad2 extends Bad{}

對(duì)代碼塊的使用break指令,使得Dart繼續(xù)執(zhí)行塊之后的語(yǔ)句。從某個(gè)角度來(lái)看,它是一個(gè)結(jié)構(gòu)化的goto,它只允許跳轉(zhuǎn)到當(dāng)前指令之后的嵌套較少的位置。

雖然聲明標(biāo)簽在代碼塊中最有用,但它們可以用在在每個(gè)語(yǔ)句中。
例如,foo: break foo;是一個(gè)有效的聲明。

請(qǐng)注意:continue上面的循環(huán)可以通過(guò)將循環(huán)體包裝到帶標(biāo)記的代碼塊中并使用break來(lái)實(shí)現(xiàn)。
也就是說(shuō),以下兩個(gè)循環(huán)是等效的:

//以下兩種描述是等價(jià)的:

// 使用 continue
for (int i = 0; i < 10; i++) {
  if (i.isEven) continue;
  print(i);
}

// 使用 break.
for (int i = 0; i < 10; i++) {
  labels: {
    // isEven 當(dāng)且僅當(dāng)該整數(shù)為偶數(shù)時(shí)才返回true
    if (i.isEven) break labels;
    print(i);
  }
}
  • 3.Switch中的標(biāo)記(label)

標(biāo)記也可以用于switch內(nèi)部。
Switch中的標(biāo)記允許continue 使用其它的case 子句。在最簡(jiǎn)單的形式中,這可以作為一種方式來(lái)實(shí)現(xiàn)下一個(gè)子句:

void switchExample(int foo) {
  switch (foo) {
    case 0:
      print("foo is 0");
      break;
    case 1:
      print("foo is 1");
      continue shared; // Continue使用在被標(biāo)記為shared的子句中
    shared:
    case 2:
      print("foo is either 1 or 2");
      break;
  }
}

有趣的是, Dart沒(méi)有要求continue的目標(biāo)子句是當(dāng)前case子句之后的子句。
帶標(biāo)記的任何case子句都是有效的目標(biāo)。這意味著,Dart的switch語(yǔ)句實(shí)際上是狀態(tài)機(jī)(state machines)。

以下示例演示了這種濫用,其中整個(gè)switch實(shí)際上只是用作狀態(tài)機(jī)(state machines)。

void main() {
  runDog();
}

void runDog() {
  int age = 0;
  int hungry = 0;
  int tired = 0;

  bool seesSquirrel() => new Random().nextDouble() < 0.1;
  bool seesMailman() => new Random().nextDouble() < 0.1;

  switch (1) {
    start:
    case 0:
      print("dog 方法已經(jīng)開始");
      print('case 0 ==> age: $age');
      print('case 0 ==> hungry: $hungry');
      print('case 0 ==> tired: $tired');
      continue doDogThings;

    sleep:
    case 1:
      print("sleeping");
      tired = 0;
      age++;
      if (age > 20) break;
      print('case 1 ==> age: $age');
      print('case 1 ==> hungry: $hungry');
      print('case 1 ==> tired: $tired');
      continue doDogThings;

    doDogThings:
    case 2:  
      if (hungry > 2) continue eat;
      if (tired > 3) continue sleep;
      if (seesSquirrel()) continue chase;
      if (seesMailman()) continue bark;
      print('case 2 ==> age: $age');
      print('case 2 ==> hungry: $hungry');
      print('case 2 ==> tired: $tired');
      continue play;

    chase:
    case 3:  
      print("chasing");
      hungry++;
      tired++;
      print('case 3 ==> age: $age');
      print('case 3 ==> hungry: $hungry');
      print('case 3 ==> tired: $tired');
      continue doDogThings;

    eat:
    case 4:  
      print("eating");
      hungry = 0;
      print('case 4 ==> age: $age');
      print('case 4 ==> hungry: $hungry');
      print('case 4 ==> tired: $tired');
      continue doDogThings;

    bark:
    case 5: 
      print("barking");
      tired++;
      print('case 5 ==> age: $age');
      print('case 5 ==> hungry: $hungry');
      print('case 5 ==> tired: $tired');
      continue doDogThings;

    play:
    case 6: 
      print("playing");
      tired++;
      hungry++;
      print('case 6 ==> age: $age');
      print('case 6 ==> hungry: $hungry');
      print('case 6 ==> tired: $tired');
      continue doDogThings;
  }
}

這個(gè)函數(shù)從一個(gè)switch子句跳到另一個(gè)子句,模擬了狗的生命。
在Dart中,標(biāo)簽只允許在case子句中使用,因此我必須添加一些case永遠(yuǎn)不會(huì)到達(dá)的行。

這個(gè)功能很酷,但很少使用。由于我們的編譯器增加了復(fù)雜性,我們經(jīng)常討論它的刪除。到目前為止,它已經(jīng)在我們的審查中幸存下來(lái),但我們最終可能會(huì)簡(jiǎn)化我們的規(guī)范并讓用戶自己添加一個(gè)while(true)循環(huán)(帶有標(biāo)記)。這個(gè)dog的示例可以重寫如下:

var state = 0;
loop:
while (true)
  switch (state) {
    case 0:
      print("dog has started");
      state = 2; continue;

    case 1:  // sleep.
      print("sleeping");
      tired = 0;
      age++;
      // The inevitable... :(
      if (age > 20) break loop;  // 跳出循環(huán)
      // Wake up and do dog things.
      state = 2; continue;
    
    case 2:  // doDogThings.
      if (hungry > 2) { state = 4; continue; }
      if (tired > 3) { state = 1; continue; }
      if (seesSquirrel()) { state = 3; continue; }
      ...

如果狀態(tài)值被命名為常量,那么它將與原始版本一樣具有可讀性,但不需要switch語(yǔ)句來(lái)支持狀態(tài)機(jī)。

(三)while 和do while

while(判斷條件){
    內(nèi)容體
}
do{
內(nèi)容體
} while(判斷條件);
while(a>5){
    print(a);
}
do{
print(a);
} while(a>5);

(四)break continue

break 停止循環(huán)

while(a>5){
  if(b>5){
  print(a);
    break;
  }
}

continue 跳到下一個(gè)循環(huán)

while(a>5){
  if(b<10){
  print(b);
    continue;
  }
}

如果使用Iterable(list或者set),則可以使用下面這種方式:

// 第一個(gè)是滿足條件就進(jìn)入  第二個(gè)是foreach遍歷
arrays
  .when((c)=>c.counts >=5)
  .foreach((c)=>c.next());

(五)switch case

比較integer, string,編譯時(shí)常量 使用==。比較對(duì)象必須是同一個(gè)類的實(shí)例(不是其子類的實(shí)例),并且該類不能重寫==。枚舉類型在switch也可以運(yùn)行。
每一條非空case字子句以break結(jié)束,也可以使用其他的方式結(jié)束:continue,throw或者return。

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();
}

(六)assert

如果布爾條件為false,則使用assert語(yǔ)句來(lái)中斷正常執(zhí)行。例如:

// 確保變量具有非空值 
assert(text != null);
// 確保值小于100
assert(number < 100);
// 確保這是一個(gè) https 網(wǎng)址
assert(urlString.startsWith('https'));

要將消息附加到斷言,請(qǐng)?zhí)砑右粋€(gè)字符串作為第二個(gè)參數(shù)。

assert(urlString.startsWith('https'),'URL ($urlString) should start with "https".');

上例中assert的第一個(gè)參數(shù)可以是任何解析為布爾值的表達(dá)式。如果表達(dá)式的值為true,則斷言成功并繼續(xù)執(zhí)行。如果為false,則斷言失敗并拋出異常


七、異常

Dart代碼可以拋出并捕獲異常。Exception是指示發(fā)生意外事件的錯(cuò)誤。如果未捕獲異常,則會(huì)暫停引發(fā)異常的isolate ,并且通常會(huì)終止isolate及其程序。

與Java相比,Dart的所有異常都是未經(jīng)檢查的異常。方法不會(huì)聲明它們可能引發(fā)的異常,并且您不需要捕獲任何異常。

Dart提供了ExceptionError 類型,以及許多預(yù)定義的子類型。當(dāng)然,您可以定義自己的Exception。但是,Dart程序可以拋出任何非null對(duì)象,作為Exception(不僅僅是Exception和Error對(duì)象)。

(一)throw

以下是拋出或引發(fā)異常的示例:

throw FormatException('Expected at least 1 section');

你也可以拋出任意對(duì)象,例如:throw '格式不正確!';
通常在開發(fā)中會(huì)拋出Error或者Exception類型。

因?yàn)閽伋霎惓J且粋€(gè)表達(dá)式,所以可以在=>語(yǔ)句中以及允許表達(dá)式的任何其他地方拋出異常:

void distanceTo(Point other) => throw UnimplementedError();   

(二)try catch

捕獲或捕獲異常會(huì)阻止異常傳遞(除非您重新拋出異常)。捕獲異常使您有機(jī)會(huì)處理它:

try {
    breedMoreLlamas();
} on OutOfLlamasException {
    buyMoreLlamas();
}

要處理可能拋出多種類型異常的代碼,可以指定多個(gè)catch子句。與拋出對(duì)象的類型匹配的第一個(gè)catch子句處理異常。如果catch子句未指定類型,則該子句可以處理任何類型的拋出對(duì)象。
您可以使用on或catch兩者兼而有之。使用on時(shí)需要指定異常類型。使用catch時(shí),你的異常處理程序需要異常對(duì)象。
示例:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

您可以指定一個(gè)或兩個(gè)參數(shù)catch()。第一個(gè)是拋出的異常,第二個(gè)是堆棧跟蹤(StackTrace對(duì)象)。
示例:

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

要部分處理異常,同時(shí)允許它傳遞,請(qǐng)使用rethrow關(guān)鍵字。
示例:

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // 運(yùn)行時(shí)異常
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // 允許調(diào)用者查看exception.
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}

(三)finally

無(wú)論是否拋出異常,要確保某些代碼運(yùn)行,請(qǐng)使用finally子句。如果沒(méi)有catch子句匹配該異常,則在finally子句運(yùn)行后傳遞異常。
示例:

try {
  breedMoreLlamas();
} finally {
  // 即使拋出異常  也會(huì)執(zhí)行這句代碼.
  cleanLlamaStalls();
}
該finally子句在任何匹配的catch子句之后運(yùn)行:
try {
  breedMoreLlamas();
} catch (e) {
    // 首先會(huì)處理異常
  print('Error: $e'); 
} finally {
  // 然后執(zhí)行這句語(yǔ)句
  cleanLlamaStalls(); 
}
最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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