語(yǔ)法學(xué)習(xí)筆記彤恶。資料參考:官方文檔(英文)
(要直接看英文文檔袋倔,中文文檔可能是機(jī)器翻譯的你踩,很多地方語(yǔ)句不通順诅岩,埋坑無(wú)數(shù))
語(yǔ)言的特性
- 所有能放進(jìn)變量中的都是對(duì)象讳苦,所有對(duì)象都是類的實(shí)例带膜,所有對(duì)象都繼承于
Object
。包含數(shù)字鸳谜,方法膝藕,null等等。也由此可以知道:沒(méi)有初始化的變量都是null咐扭;沒(méi)有裝箱拆箱的問(wèn)題芭挽。 - Dart是強(qiáng)類型語(yǔ)言。你可以顯示聲明類型蝗肪,也可以直接使用
var
袜爪,Dart會(huì)自動(dòng)推斷類型。當(dāng)你要聲明一個(gè)不確定類型的變量時(shí)薛闪,可以使用特殊類型dynamic
來(lái)聲明辛馆。 - 支持頂級(jí)方法,類方法豁延,嵌套方法(在方法中聲明方法)
- 沒(méi)有其他語(yǔ)言的public等關(guān)鍵字昙篙,但如果一個(gè)標(biāo)識(shí)符以 "_" 開頭,則為私有诱咏。
-
new
關(guān)鍵字是可選的苔可。
內(nèi)置類型
numbers:帶小數(shù)點(diǎn)的就是double,不帶的就是int
-
Strings:
1.創(chuàng)建既可以用""
也可以用''
袋狞;
2.編碼是UTF-16焚辅;
3.可以使用"${xxx}"
來(lái)格式化輸出字符串,其中的{}
一般情況下可以省略苟鸯,eg."a = $a"
"a = ${a}."
"a = ${a}ah"
法焰,其中最后一個(gè)需要加{}
是因?yàn)槿绻患?code>{},相當(dāng)于"a = $aah"
倔毙,使用的值是aah
埃仪,而不是a
;- 多行字符串
''' xxxx '''
或者""" xxx """
-
r'\n'
輸出的是\n
陕赃。其中r
取消字符串中的轉(zhuǎn)義字符卵蛉。
- 多行字符串
Booleans:不允許使用
if(0)
之類的代碼颁股,會(huì)編譯報(bào)錯(cuò)。-
Lists:
- 索引從0開始
- 使用
const
創(chuàng)建的list傻丝,該變list中的單個(gè)元素會(huì)運(yùn)行報(bào)錯(cuò)甘有。
var list = const[1, 2, 3, 4]; list[0] = 12;//這里報(bào)錯(cuò)
- 可以在list創(chuàng)建時(shí)使用
if
和for
。bool isAddExtraElement = false; var list = [ 0, 1, if(isAddExtraElement) 2 ]; print(list.toString()); var list2 = [ for(int i=0; i < list.length; i++) "forElement:${list[i]}" ]; print(list2);
-
Sets:無(wú)序列表
- 創(chuàng)建
//var test = {}; //這樣聲明的是map葡缰,不是set var test = <String>{}; var test1 = {"a", "b", "c", "d", "e"}; var test2 = <String>{}; test2.add("f"); test2.addAll(test1);
- 一樣可以用
const
進(jìn)行創(chuàng)建亏掀,使用const
創(chuàng)建的set不能更改。
- 創(chuàng)建
-
Maps:字典
- 創(chuàng)建
var map1 = { 1: 15, 2: 16, 3: 17, 4: 18 }; map1[5] = 19; var map2 = Map(); map2["q"] = 1; map2["w"] = 2; map2["e"] = 3;
- 可以使用
const
進(jìn)行創(chuàng)建泛释,使用const
創(chuàng)建的Map不能更改滤愕。
- 創(chuàng)建
Runes:使用4位16進(jìn)制數(shù)可以輸出一些特殊字符。但一般好像沒(méi)什么卵用怜校。
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(new String.fromCharCodes(input));
輸出: ? ?? ?? ?? ?? ??
- Symbols:不清楚這個(gè)東西是干嘛的间影,好像也沒(méi)什么卵用。
函數(shù)
- 函數(shù)的返回值類型可以省略茄茁,下面兩個(gè)函數(shù)是一樣的魂贬。
add(num a, num b) {
return a + b;
}
num add(num a, num b) {
return a + b;
}
- 不定參數(shù)
```
add(num a, num b, [num c = 0, num d]) {//[]中是不定參數(shù),其中c帶默認(rèn)值
return a + b + c + (d ?? 0);
}
sub({num a = 0, num b = 0, num c}){//{}中是不定參數(shù)裙顽,其中a, b帶默認(rèn)值
return a - b - (c ?? 0);
}
main(List<String> arguments) {
print(add(1, 2, 3));//和其他語(yǔ)言使用方法一致
print(sub(b : 2, a : 1));//傳入?yún)?shù)是按照key值對(duì)應(yīng)的付燥,不用考慮順序。&&個(gè)人認(rèn)為這種方式使用有些麻煩愈犹。
}
```
- 函數(shù)能夠直接當(dāng)做變量進(jìn)行傳遞键科,類似于C#中的Action,但不用額外進(jìn)行變量的定義甘萧。
- 匿名函數(shù)萝嘁,使用lamda表達(dá)式,語(yǔ)法與C#基本一致扬卷。
- 值的一看的官方閉包的例子牙言,用函數(shù)創(chuàng)建函數(shù)。
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
關(guān)于++i
和i++
和其他語(yǔ)言的一樣怪得。
這里只是簡(jiǎn)單記錄一下咱枉,順便復(fù)習(xí),&&知道這么個(gè)東西就行了徒恋,開發(fā)中不要用蚕断,不差多一行代碼。
話說(shuō)誰(shuí)要是在寫代碼的時(shí)候抖這個(gè)機(jī)靈入挣,不出bug一切安好亿乳,一旦出bug可能讓你查到天荒地老。
官方例子
var a, b;
a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1
a = 0;
b = a++; // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0
a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1
a = 0;
b = a--; // Decrement a AFTER b gets its value.
assert(a != b); // -1 != 0
總之:a
靠近=
==> 先賦值
流程控制
if(xxx){} else if(xxx) {} else{}
-
for(int i = 0; i < xxx.Length; i++)
&&for(var a in xxx)
。for ... in
的用法基本等同于C#中的foreach
-
while(xxx){}
&&do{}while{xxx}
-
switch case
基本用法與C#一樣葛假,但有一個(gè)額外的用法
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;//強(qiáng)制繼續(xù)執(zhí)行下面的case障陶。個(gè)別地方可能會(huì)省一些代碼。
// Continues executing at the nowClosed label.
nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
-
assert
false時(shí)中斷程序聊训,拋出異常抱究。
拋出異常
throw 'something error !!!'
,可以直接寫異常信息带斑。(當(dāng)然也可以指定異常類型)
異常捕獲
try...catch...finally
用法基本與C#的相同鼓寺,但個(gè)別的語(yǔ)法不一樣
try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e, s) {
// No specified type, handles all
print('Something really unknown: $e $s');
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
類
一般類的定義和使用和C#基本一致。需要注意下沒(méi)有public等關(guān)鍵字就好了勋磕。下面記一下有區(qū)別的地方妈候。
- 構(gòu)造函數(shù)
- 純類名構(gòu)造函數(shù)只允許有一個(gè)。默認(rèn)為
ClassName()
朋凉。父類額外定義的構(gòu)造函數(shù)州丹,子類至少要繼承聲明一個(gè)醋安。 - 特有的構(gòu)造函數(shù)聲明方法
class Point { num x, y; Point(this.x, this.y);//省略賦值杂彭。這種方式的構(gòu)造函數(shù)只能有一個(gè)。 Point.origin() {//命名構(gòu)造函數(shù)吓揪,使用時(shí)調(diào)用Point.origin()即可亲怠。多個(gè)構(gòu)造函數(shù)可以用此定義。 x = 0; y = 0; } }
- 構(gòu)造函數(shù)不能自動(dòng)繼承柠辞,需要手動(dòng)實(shí)現(xiàn)团秽。
class Animal { num age; Animal(this.age);//定義初始構(gòu)造函數(shù),唯一 Animal.normal() : this(0);//使用默認(rèn)構(gòu)造函數(shù) Animal.dead() { age = 9999; } } class Dog extends Animal { Dog(num age) : super(age);//至少實(shí)現(xiàn)一個(gè) }
-
initializer list:冒號(hào)后面的部分叭首。構(gòu)造時(shí)優(yōu)先執(zhí)行习勤。可以在這里進(jìn)行一些數(shù)據(jù)的初始處理或者判斷焙格。多條使用
,
隔開图毕。
class Point{ num x; num y; Point(num x, num y) : assert(x != 0 || y != 0) {//數(shù)據(jù)錯(cuò)誤檢查 this.x = x; this.y = y; } Point.original() : x = 0, y = 0 {//數(shù)據(jù)初始值賦值 print("create default point"); } }
- 創(chuàng)建對(duì)象時(shí),構(gòu)造函數(shù)的執(zhí)行順序眷唉。initializer list-->父類構(gòu)造函數(shù)-->子類構(gòu)造函數(shù)
-
Const
構(gòu)造函數(shù)予颤。要求使用時(shí)需要類中有final量。
class Point{ final num x; final num y; const Point(this.x, this.y); const Point.test(this.x, this.y); } main(List<String> arguments) { var point = Point(15, 16); var point2 = Point(15, 16); print(point == point2);//false var point3 = const Point(1, 1); var point4 = const Point(1, 1); print(point3 == point4);//true var point5 = const Point(1, 2); var point6 = const Point(1, 3); print(point5 == point6);//false var point7 = const Point.test(1, 2); var point8 = const Point(1, 2); print(point7 == point8);//true }
-
factory
構(gòu)造函數(shù)
class Message { String content; static final Map<String, Message> _map = {};//靜態(tài)緩存 factory Message(String content) { return _map.putIfAbsent(content, ()=>Message._internal(content));//找不到則執(zhí)行該方法進(jìn)行添加 } Message._internal(this.content);//內(nèi)部調(diào)用的構(gòu)造函數(shù) } main(List<String> arguments) { var message1 = Message("asd"); var message2 = Message("asd"); print(message1 == message2);//true var message3 = Message("asd3"); print(message1 == message3);//false }
- 純類名構(gòu)造函數(shù)只允許有一個(gè)。默認(rèn)為
- 屬性
class Message {
String _content = "";
get content => _content;
set content(String value) => _content = value;
get content2 { return _content; }
set content2(String value) { _content = value; }
}
main(List<String> arguments) {
var message = Message();
print(message.content);
print(message.content2);
message.content = "hello world";
print(message.content);
message.content2 = "hello world2";
print(message.content2);
}
- 抽象類:關(guān)鍵字
abstract
與C#一樣冬阳,只有抽象類中才能有抽象屬性蛤虐,方法。
abstract class Message {
String _content = "";
get content;
func();
func2(){//有實(shí)現(xiàn)的不算抽象方法
return 16;
}
}
class Message2 extends Message{
@override
func() {
// TODO: implement func
return null;
}
@override
// TODO: implement content
get content => null;
}
- 類的繼承
使用extends
關(guān)鍵字肝陪。子類中重新實(shí)現(xiàn)了父類的方法的話默認(rèn)重載驳庭。如果真的需要重載的話,記得最好加上@overrider
氯窍。另外饲常,需要的話記得加上super.xxx()
來(lái)調(diào)用父類的方法捏检。下面是例子:
class Add{
num add(num a, num b){
return a + b;
}
test(){}
}
class SubAdd extends Add{
@override
num add(num a, num b){
super.test();
super.add(a, b);
return a * b;
}
}
main(List<String> arguments) {
var test = SubAdd();
print(test.add(10, 20));
}
- Implicit接口
Dart中沒(méi)有像C#中的Interface的關(guān)鍵字,但Dart的每一個(gè)類都相當(dāng)于定義了一個(gè)隱式的接口不皆。如果ClassA想實(shí)現(xiàn)ClassB的功能贯城,那么ClassA需要implements
ClassB。下面是例子:
class Add{
num add(num a, num b){
return a + b;
}
num other(num a, num b){
return (a + b) / (a - b);
}
}
class Sub{
num sub(num a, num b){
return a - b;
}
}
class Calculation implements Add, Sub{//implements后面的類霹娄,僅僅作為接口能犯,接口需要自己額外進(jìn)行實(shí)現(xiàn),和原來(lái)的類里有沒(méi)有實(shí)現(xiàn)沒(méi)關(guān)系
@override
num add(num a, num b) {
return a + b;
}
@override
num other(num a, num b) {
return a * b;
}
@override
num sub(num a, num b) {
return a - b;
}
}
main(List<String> arguments) {
var calculation = Calculation();
print(calculation.add(10, 20));
print(calculation.other(10, 20));
print(calculation.sub(10, 20));
}
- Static:用法和C#一樣犬耻,但有些需要注意的點(diǎn)踩晶。
- 類中的靜態(tài)變量,如果從沒(méi)有被使用過(guò)枕磁,它是不初始化的渡蜻。
- 類中的靜態(tài)方法,如果可以的話计济,推薦將靜態(tài)方法改成頂級(jí)方法茸苇。
枚舉類型
與C#基本一樣
enum Color {
Red,//不能像C#一樣額外定義枚舉的Index值
Green,
Blue,
Yellow,
}
main(List<String> arguments) {
var colors = Color.values;//轉(zhuǎn)成list,可以用index來(lái)取
for(var a in colors){
print(a);
}
}
Mixins
我額外參考的一篇文章沦寂,說(shuō)明的很詳細(xì)具體学密,推薦閱讀:【譯】Dart | 什么是Mixin
幾個(gè)重要的關(guān)鍵字:mixin
on
with
,相關(guān)的內(nèi)容在下面的例子里注釋說(shuō)明传藏。
覺(jué)得這個(gè)功能在有些時(shí)候會(huì)很有用腻暮,但現(xiàn)在自己還沒(méi)有實(shí)際操作過(guò),理解不夠毯侦,只能先記下來(lái)哭靖,留著以后再補(bǔ)充了。
class DoA{
factory DoA._(){//這里通過(guò)工廠方式侈离,禁止外部創(chuàng)建试幽。當(dāng)然也可以根據(jù)需求允許創(chuàng)建
return null;
}
void canDoSomethingA(){
print("do A");
}
}
mixin DoB{//mixin關(guān)鍵字,使該類沒(méi)有構(gòu)造器霍狰,無(wú)法被創(chuàng)建抡草。
void canDoSomethingB(){
print("do B");
}
}
mixin DoC{
void canDoSomethingC(){
print("do C");
}
}
mixin DoD on Person {//mixin...on... ,相當(dāng)于 class ... extends ...
void canDoSomethingD(){
print("do D");
}
}
class Person {
void Say(String content){
print("Say : $content");
}
}
class Person1 extends Person with DoA, DoB {}
class Person2 extends Person with DoB, DoC {}
class Person3 extends Person with DoC, DoD {}
main(List<String> arguments) {
var person1 = Person1();
print(person1);
person1.canDoSomethingA();
person1.canDoSomethingB();
print(person1 is Person);//true
print(person1 is DoA);//true
print(person1 is DoB);//true
var person2 = Person2();
print(person2);
person2.canDoSomethingB();
person2.canDoSomethingC();
var person3 = Person3();
print(person3);
person3.canDoSomethingC();
person3.canDoSomethingD();
person3.Say("Hello World");
}
泛型
和C#中的泛型用法相同蔗坯,但是約束語(yǔ)法不一樣康震,也不能像C#一樣有多個(gè)約束條件(因?yàn)镈art中沒(méi)有接口)。
下面是例子:
class Person {}
class Test<T extends Person>{
void Record(){
print(T);
}
K DoSomething<K extends num>(K value){
print("$K $value");
return value * 2;
}
}
main(List<String> arguments) {
var test = Test<Person>();
test.Record();
print(test.DoSomething<int>(10));
print(test.DoSomething<double>(10.11));
}
Libraries
通俗的講宾濒,就是通過(guò)導(dǎo)入的方式腿短,來(lái)使用其他腳本里的方法,類,變量等等橘忱。
-
import 'xxxx' [as xxx] [show aaa[, aaa2, aaa3]] [hide bbb[, bbb1, bbb2, bbb3]];
方括號(hào)中表示可選赴魁。
其中:as
表示定義lib使用時(shí)前綴,show
表示將lib中指定的方法钝诚、類進(jìn)行導(dǎo)出颖御,hide
表示將指定的方法、類進(jìn)行隱藏凝颇。 -
deferred as
潘拱,表示使用時(shí)再導(dǎo)入(Flutter 不支持)。
import 'package:dart_demo/dart_demo.dart' deferred as dart_demo;
Future load(Function action) async{
await dart_demo.loadLibrary();
action();
}
main(List<String> arguments) {
load(()=>print(dart_demo.calculate1()));
}
異步
- 一般異步:
關(guān)鍵字async
await
loadRes(String path) async{ print(path); } initRes() async{ await loadRes("path1"); await loadRes("path2"); await loadRes("path3"); } main(List<String> arguments) { var future = initRes(); future.whenComplete(()=>print("finished")); }
- 流
其實(shí)和上面的一樣拧略,就是await在流里面有個(gè)特殊用法芦岂。read() async { try { var path = r"C:\Users\Admin\Desktop\test.txt"; var file = File(path); var stream = file.openRead(); await for(var a in stream) { //等待流讀取 print(a); } } catch(e) { print(e); } } main(List<String> arguments) { read(); }
其他的零碎東西
需要額外記的關(guān)鍵字
- final 相當(dāng)于 C#中的 readonly〉媲可以直接用final進(jìn)行變量的聲明禽最,而不用額外去指定變量類型。eg.
final a = 15;
- const袱饭,除了其他一般語(yǔ)言的編譯時(shí)常量的用法以外川无,還可以用來(lái)創(chuàng)建不可改變的值。eg.
var list = const [];
-
is!
:obj is! TypeA
如果obj
不是TypeA
類型則返回true
-
..
:一個(gè)語(yǔ)法糖宁赤,讓你能夠?qū)σ粋€(gè)對(duì)象進(jìn)行連續(xù)的一些列操作舀透,而不用額外去寫對(duì)象的變量名稱栓票。下面是官方例子决左,兩組表達(dá)式進(jìn)行的操作是完全相同的。支持嵌套(這個(gè)個(gè)人不推薦走贪,嵌套太多容易出坑)佛猛。querySelector('#confirm') // Get an object. ..text = 'Confirm' // Use its members. ..classes.add('important') ..onClick.listen((e) => window.alert('Confirmed!')); var button = querySelector('#confirm'); button.text = 'Confirm'; button.classes.add('important'); button.onClick.listen((e) => window.alert('Confirmed!'));
-
?=
:b ?= 5;
,如果b
是null
坠狡,則將b
賦值為5
继找,如果b
不是null
,則b
保持原樣逃沿。 -
~/
:整除 -
~
:按位取反
Generators
關(guān)鍵字:sync*
async*
yield
yield*
- 同步的返回Iterable<T>婴渡,類似于C#中的IEnumerable<T>
Iterable<int> test() sync* {//sync* 標(biāo)記當(dāng)前函數(shù)為Generators函數(shù),返回Iterable<T> 類型
for(int i=0;i<100;i++) {
yield i;//表示將什么值放進(jìn)Iterable<T>里面
}
}
- 異步的返回Stream<T>
Stream<int> test(int startNum) async* { //async*標(biāo)記函數(shù)為異步的Generators凯亮,返回Stream<T>
if(startNum < 10) {
yield startNum;
yield* test(startNum + 1); //遞歸要用yield*
}
}
main(List<String> arguments) async {
var st = test(1);
await for(var a in st) {
print(a);
}
}
Callable classes
可以像使用函數(shù)一樣使用這種類的對(duì)象边臼。
class Test {
String content;
Test(this.content);
call(String other) => "$other $content";//實(shí)現(xiàn)call方法后,示例的對(duì)象可以作為函數(shù)對(duì)象來(lái)使用假消∧ⅲ可以有傳參,也可以沒(méi)有
}
main(List<String> arguments) async {
var t = Test("hello world");
print(t("Tina"));//使用執(zhí)行函數(shù)的方式,調(diào)用類中的call()方法
}
Isolates
目前的簡(jiǎn)單理解是多線程臼予,不一定正確&需要進(jìn)行實(shí)踐鸣戴。等后面遇到了,理解了再將筆記補(bǔ)上粘拾。
Typedefs
目前的理解窄锅,是給函數(shù)的類型定一個(gè)別名。感覺(jué)形式上有點(diǎn)像C#里面的委托缰雇。
typedef num Calculate(num a, num b);//將這種類型的函數(shù)定義為Calculate類型的函數(shù)
num add(num x, num y) => x + y;
sub(num x, num y) => x - y;
main(List<String> arguments) async {
print(add is Calculate);//true
print(sub is Calculate);//false
}
Metadata
- 使用
Metadata能夠在類酬滤,變量,參數(shù)寓涨,函數(shù)等等的前面使用盯串。運(yùn)行時(shí),可以通過(guò)反射獲取到Metadata戒良。
class Television {
/// _Deprecated: Use [turnOn] instead._
@deprecated//表示這個(gè)函數(shù)方法被棄用
void activate() {
turnOn();
}
/// Turns the TV's power on.
void turnOn() {...}
}
- 創(chuàng)建
官方例子
library todo;
class Todo {
final String who;
final String what;
const Todo(this.who, this.what);
}
import 'todo.dart';
@Todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
注釋
需要說(shuō)的就是文檔注釋体捏,其他的和C#一樣。
方括號(hào)中表示變量
/// Exercises your llama with an [activity] for
/// [timeLimit] minutes.
void exercise(Activity activity, int timeLimit) {
// ...
}
官方文檔糯崎,基礎(chǔ)的部分算是看完了几缭。后面實(shí)際操作中發(fā)現(xiàn)有問(wèn)題會(huì)進(jìn)行補(bǔ)充和修改。
如果有人看的話沃呢,發(fā)現(xiàn)錯(cuò)誤歡迎指正年栓。
另外發(fā)現(xiàn)ide的自動(dòng)格式化有些不好用,有好用的ide也歡迎推薦薄霜。