推薦個(gè)小工具:Flutter自動生成widget代碼 停团,只支持pc瀏覽器(不包括edge哭懈,ie)
注意:
跟Java等很多語言不同的是凿渊,Dart沒有public protected private等關(guān)鍵字笼呆,如果某個(gè)變量以下劃線 _ 開頭,代表這個(gè)變量在庫中是私有的昧碉。Dart中變量可以以字母或下劃線開頭英染,后面跟著任意組合的字符或數(shù)字
變量
變量定義
以下代碼是Dart中定義變量的方法:
main() {
var a = 1;
int b = 10;
String s = "hello";
dynamic c = 0.5;
}
你可以明確指定某個(gè)變量的類型,如int bool String被饿,也可以用var或 dynamic來聲明一個(gè)變量四康,Dart會自動推斷其數(shù)據(jù)類型。
final和const
如果你絕不想改變一個(gè)變量狭握,使用final或const闪金,不要使用var或其他類型,一個(gè)被final修飾的變量只能被賦值一次论颅,一個(gè)被const修飾的變量是一個(gè)編譯時(shí)常量(const常量毫無疑問也是final常量)哎垦。可以這么理解:final修飾的變量是不可改變的恃疯,而const修飾的表示一個(gè)常量漏设。
注意:實(shí)例變量可以是final的但不能是const的
下面用代碼說明:
var count = 10;
final Num = count; // final 只能賦值一次
const Num1 = 10; // const賦值必須是編譯時(shí)常量
final和const的區(qū)別:
區(qū)別一:final 要求變量只能初始化一次,并不要求賦的值一定是編譯時(shí)常量今妄,可以是常量也可以不是郑口。而 const 要求在聲明時(shí)初始化,并且賦值必需為編譯時(shí)常量蛙奖。
區(qū)別二:final 是惰性初始化潘酗,即在運(yùn)行時(shí)第一次使用前才初始化杆兵。而 const 是在編譯時(shí)就確定值了雁仲。
內(nèi)建數(shù)據(jù)類型
Dart有如下幾種內(nèi)建的數(shù)據(jù)類型:
- numbers
- strings
- booleans
- lists(或者是arrays)
- maps
- runes(UTF-32字符集的字符)
- symbols
下面用一段代碼來演示以上各類數(shù)據(jù)類型:
main() {
// numbers
var a = 0;
int b = 1;
double c = 0.1;
// strings
var s1 = 'hello';
String s2 = "world";
// booleans
var real = true;
bool isReal = false;
// lists
var arr = [1, 2, 3, 4, 5];
List<String> arr2 = ['hello', 'world', "123", "456"];
List<dynamic> arr3 = [1, true, 'haha', 1.0];
// maps
var map = new Map();
map['name'] = 'zhangsan';
map['age'] = 10;
Map m = new Map();
m['a'] = 'a';
//runes,Dart 中 使用runes 來獲取UTF-32字符集的字符琐脏。String的 codeUnitAt and codeUnit屬性可以獲取UTF-16字符集的字符
var clapping = '\u{1f44f}';
print(clapping); // 打印的是拍手emoji的表情
// symbols
print(#s == new Symbol("s")); // true
}
函數(shù)
函數(shù)的返回值
Dart是一個(gè)面向?qū)ο蟮木幊陶Z言攒砖,所以即使是函數(shù)也是一個(gè)對象缸兔,也有一種類型Function,這就意味著函數(shù)可以賦值給某個(gè)變量或者作為參數(shù)傳給另外的函數(shù)吹艇。雖然Dart推薦你給函數(shù)加上返回值惰蜜,但是不加返回值的函數(shù)同樣可以正常工作,另外你還可以用=>代替return語句受神,比如下面的代碼:
// 聲明返回值
int add(int a, int b) {
return a + b;
}
// 不聲明返回值
add2(int a, int b) {
return a + b;
}
// =>是return語句的簡寫
add3(a, b) => a + b;
main() {
print(add(1, 2)); // 3
print(add2(2, 3)); // 5
print(add3(1, 2)); // 3
}
命名參數(shù)抛猖、位置參數(shù)、參數(shù)默認(rèn)值
命名參數(shù)
sayHello({String name}) {
print("hello, my name is $name");
}
sayHello2({name: String}) {
print("hello, my name is $name");
}
main() {
// 打印 hello, my name is zhangsan
sayHello(name: 'zhangsan');
// 打印 hello, my name is wangwu
sayHello2(name: 'wangwu');
}
可以看到鼻听,定義命名參數(shù)時(shí)财著,你可以以 {type paramName}
或者 {paramName: type}
兩種方式聲明參數(shù),而調(diào)用命名參數(shù)時(shí)撑碴,需要以 funcName(paramName: paramValue)
的形式調(diào)用撑教。
命名參數(shù)的參數(shù)并不是必須的,所以上面的代碼中醉拓,如果調(diào)用sayHello()不帶任何參數(shù)伟姐,也是可以的,只不過最后打印出來的結(jié)果是:hello, my name is null亿卤,在Flutter開發(fā)中愤兵,你可以使用@required注解來標(biāo)識一個(gè)命名參數(shù),這代表該參數(shù)是必須的排吴,你不傳則會報(bào)錯恐似,比如下面的代碼:
const Scrollbar({Key key, @required Widget child})
位置參數(shù)
使用中括號[]括起來的參數(shù)是函數(shù)的位置參數(shù),代表該參數(shù)可傳可不傳傍念,位置參數(shù)只能放在函數(shù)的參數(shù)列表的最后面矫夷,如下代碼所示:
sayHello(String name, int age, [String hobby]) { // 位置參數(shù)可以有多個(gè),比如[String a, int b]
StringBuffer sb = new StringBuffer();
sb.write("hello, this is $name and I am $age years old");
if (hobby != null) {
sb.write(", my hobby is $hobby");
}
print(sb.toString());
}
main() {
// hello, this is zhangsan and I am 20 years old
sayHello("zhangsan", 20);
// hello, this is zhangsan and I am 20 years old, my hobby is play football
sayHello("zhangsan", 20, "play football");
}
參數(shù)默認(rèn)值
你可以為命名參數(shù)或者位置參數(shù)設(shè)置默認(rèn)值憋槐,如下代碼所示:
// 命名參數(shù)的默認(rèn)值
int add({int a, int b = 3}) { // 不能寫成:int add({a: int, b: int = 3})
return a + b;
}
// 位置參數(shù)的默認(rèn)值
int sum(int a, int b, [int c = 3]) {
return a + b + c;
}
main()函數(shù)
不論在Dart還是Flutter中双藕,必須都需要一個(gè)頂層的main()函數(shù),它是整個(gè)應(yīng)用的入口函數(shù)阳仔,main()函數(shù)的返回值是void忧陪,還有一個(gè)可選的參數(shù),參數(shù)類型是List<String>近范。
函數(shù)作為一類對象
你可以將一個(gè)函數(shù)作為參數(shù)傳給另一個(gè)函數(shù)嘶摊,比如下面的代碼:
printNum(int a) {
print("$a");
}
main() {
// 依次打印:
// 1
// 2
// 3
var arr = [1, 2, 3];
arr.forEach(printNum);
}
你也可以將一個(gè)函數(shù)賦值給某個(gè)變量评矩,比如下面的代碼:
printNum(int a) {
print("$a");
}
main() {
var f1 = printNum;
Function f2 = printNum;
var f3 = (int a) => print("a = $a");
f1(1);
f2(2);
f3(6);
}
匿名函數(shù)
大多數(shù)函數(shù)都是有名稱的叶堆,比如main() printName()等,但是你也可以寫匿名函數(shù)斥杜,如果你對Java比較熟悉虱颗,那下面的Dart代碼你肯定也不會陌生:
test(Function callback) {
callback("hello");
}
main() {
test((param) {
// 打印hello
print(param);
});
}
匿名函數(shù)類似于Java中的接口沥匈,往往在某個(gè)函數(shù)的參數(shù)為函數(shù)時(shí)使用到。
函數(shù)返回值
所有的函數(shù)都有返回值忘渔,如果沒有指定return語句高帖,那么該函數(shù)的返回值為null。
運(yùn)算符
Dart中的運(yùn)算符與Java中的類似畦粮,比如++a a == b b ? a : b散址,但是也有一些與Java不太一樣的運(yùn)算符,下面用代碼說明:
main() {
// 與Java相同的運(yùn)算符操作
int a = 1;
++a;
a++;
var b = 1;
print(a == b); // false
print(a * b); // 3
bool real = false;
real ? print('real') : print('not real'); // not real
print(real && a == b); // false
print(real || a == 3); // true
print(a != 2); // true
print(a <= b); // false
var c = 9;
c += 10;
print("c = $c"); // c = 19
print(1<<2); // 4
// 與Java不太一樣的運(yùn)算符操作
// is運(yùn)算符用于判斷一個(gè)變量是不是某個(gè)類型的數(shù)據(jù)
// is!則是判斷變量不是某個(gè)類型的數(shù)據(jù)
var s = "hello";
print(s is String); // true
var num = 6;
print(num is! String); // true
// ~/才是取整運(yùn)算符宣赔,如果使用/則是除法運(yùn)算爪飘,不取整
int k = 1;
int j = 2;
print(k / j); // 0.5
print(k ~/ j); // 0
// as運(yùn)算符類似于Java中的cast操作,將一個(gè)對象強(qiáng)制類型轉(zhuǎn)換
(emp as Person).teach();
// ??=運(yùn)算符 如果 ??= 運(yùn)算符前面的變量為null拉背,則賦值师崎,否則不賦值
var param1 = "hello", param2 = null;
param1 ??= "world";
param2 ??= "world";
print("param1 = $param1"); // param1 = hello
print("param2 = $param2"); // param2 = world
// ?.運(yùn)算符
var str1 = "hello world";
var str2 = null;
print(str1?.length); // 11
print(str2?.length); // null
print(str2.length); // 報(bào)錯
}
…運(yùn)算符(級聯(lián)操作)
如果你對Java中的建造者模式比較熟悉的話,Dart中的…運(yùn)算符也很好理解椅棺,先看下面的代碼:
class Person {
eat() {
print("I am eating...");
}
sleep() {
print("I am sleeping...");
}
study() {
print("I am studying...");
}
}
main() {
// 依次打印
// I am eating...
// I am sleeping...
// I am studying...
new Person()..eat()
..sleep()
..study();
}
可以看到犁罩,使用…調(diào)用某個(gè)對象的方法(或者成員變量)時(shí),返回值是這個(gè)對象本身两疚,所以你可以接著使用…調(diào)用這個(gè)對象的其他方法床估,這不就類似于Java中的建造者模式,每次build某個(gè)屬性時(shí)诱渤,都返回一個(gè)this對象嗎丐巫。
控制流程
if / else switch for /while try / catch語句跟Java中都類似,try / catch語句可能稍有不同勺美,下面用一段代碼說明:
main() {
// if else語句
int score = 80;
if (score < 60) {
print("so bad!");
} else if (score >= 60 && score < 80) {
print("just so so!");
} else if (score >= 80) {
print("good job!");
}
// switch語句
String a = "hello";
// case語句中的數(shù)據(jù)類型必須是跟switch中的類型一致
switch (a) {
case "hello":
print("haha");
break;
case "world":
print("heihei");
break;
default:
print("WTF");
}
// for語句
List<String> list = ["a", "b", "c"];
for (int i = 0; i < list.length; i++) {
print(list[i]);
}
for (var i in list) {
print(i);
}
// 這里的箭頭函數(shù)參數(shù)必須用圓括號擴(kuò)起來
list.forEach((item) => print(item));
// while語句
int start = 1;
int sum = 0;
while (start <= 100) {
sum += start;
start++;
}
print(sum);
// try catch語句
try {
print(1 ~/ 0);
} catch (e) {
// IntegerDivisionByZeroException
print(e);
}
try {
1 ~/ 0;
} on IntegerDivisionByZeroException { // 捕獲指定類型的異常
print("error"); // 打印出error
} finally {
print("over"); // 打印出over
}
}
類(Class)
類的定義與構(gòu)造方法
Dart中的類沒有訪問控制递胧,所以你不需要用private, protected, public等修飾成員變量或成員函數(shù),一個(gè)簡單的類如下代碼所示:
class Person {
String name;
int age;
String gender;
Person(this.name, this.age, this.gender);
sayHello() {
print("hello, this is $name, I am $age years old, I am a $gender");
}
}
上面的Person類中有3個(gè)成員變量赡茸,一個(gè)構(gòu)造方法和一個(gè)成員方法缎脾,看起來比較奇怪的是Person的構(gòu)造方法,里面?zhèn)魅氲?個(gè)參數(shù)都是http://this.xxx占卧,而且沒有大括號{}包裹的方法體遗菠,這種語法是Dart比較獨(dú)特而簡潔的構(gòu)造方法聲明方式,它等同于下面的代碼:
Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
要調(diào)用Person類的成員變量或成員方法华蜒,可以用下面的代碼:
var p = new Person("zhangsan", 20, "male");
p.sayHello(); // hello, this is zhangsan, I am 20 years old, I am a male
p.age = 50;
p.gender = "female";
p.sayHello(); // hello, this is zhangsan, I am 50 years old, I am a female
類除了有跟類名相同的構(gòu)造方法外辙纬,還可以添加命名的構(gòu)造方法,如下代碼所示:
class Point {
num x, y;
Point(this.x, this.y);
// 類的命名構(gòu)造方法
Point.origin() {
x = 0;
y = 0;
}
}
main() {
// 調(diào)用Point類的命名構(gòu)造方法origin()
var p = new Point.origin();
var p2 = new Point(1, 2);
}
Dart中使用extends關(guān)鍵字做類的繼承叭喜,如果一個(gè)類只有命名的構(gòu)造方法贺拣,在繼承時(shí)需要注意,如下代碼:
class Human {
String name;
Human.fromJson(Map data) {
print("Human's fromJson constructor");
}
}
class Man extends Human {
Man.fromJson(Map data) : super.fromJson(data) {
print("Man's fromJson constructor");
}
}
由于Human類沒有默認(rèn)構(gòu)造方法域滥,只有一個(gè)命名構(gòu)造方法fromJson纵柿,所以在Man類繼承Human類時(shí),需要調(diào)用父類的fromJson方法做初始化启绰,而且必須使用Man.fromJson(Map data) : super.fromJson(data)這種寫法昂儒,而不是像Java那樣將super寫到花括號中。
有時(shí)候你僅僅只是在某個(gè)類的構(gòu)造方法中委可,調(diào)用這個(gè)類的另一個(gè)構(gòu)造方法渊跋,你可以這么寫:
class Point {
num x, y;
Point(this.x, this.y);
// 命名構(gòu)造方法調(diào)用了默認(rèn)的構(gòu)造方法
Point.alongXAxis(num x) : this(x, 0);
}
類的成員方法
一個(gè)類的成員方法是一個(gè)函數(shù),為這個(gè)類提供某些行為着倾。上面的代碼中已經(jīng)有了一些類的成員方法的定義拾酝,這些定義方式跟Java很類似践叠,你可以為某個(gè)類的成員變量提供getter/setter方法柬焕,如下代碼:
class Rectangle {
num left, top, width, height;
// 構(gòu)造方法傳入left, top, width, height幾個(gè)參數(shù)
Rectangle(this.left, this.top, this.width, this.height);
// right, bottom兩個(gè)成員變量提供getter/setter方法
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
抽象類和抽象方法
使用abstract修飾一個(gè)類更啄,則這個(gè)類是抽象類鳖谈,抽象類中可以有抽象方法和非抽象方法穿铆,抽象方法沒有方法體逻炊,需要子類去實(shí)現(xiàn)键闺,如下代碼:
abstract class Doer {
// 抽象方法汗捡,沒有方法體恒傻,需要子類去實(shí)現(xiàn)
void doSomething();
// 普通的方法
void greet() {
print("hello world!");
}
}
class EffectiveDoer extends Doer {
// 實(shí)現(xiàn)了父類的抽象方法
void doSomething() {
print("I'm doing something...");
}
}
運(yùn)算符重載
Dart中有類似于C++中的運(yùn)算符重載語法脸侥,比如下面的代碼定義了一個(gè)向量類,重載了向量的+ -運(yùn)算:
class Vector {
num x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => new Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => new Vector(x - v.x, y - v.y);
printVec() {
print("x: $x, y: $y");
}
}
main() {
Vector v1 = new Vector(1, 2);
Vector v2 = new Vector(3, 4);
(v1 - v2).printVec(); // -2, -2
(v1 + v2).printVec(); // 4, 6
}
枚舉類
使用enum關(guān)鍵字定義一個(gè)枚舉類盈厘,這個(gè)語法跟Java類似睁枕,如下代碼:
enum Color { red, green, blue }
mixins
mixins是一個(gè)重復(fù)使用類中代碼的方式,比如下面的代碼:
class A {
a() {
print("A's a()");
}
}
class B {
b() {
print("B's b()");
}
}
// 使用with關(guān)鍵字沸手,表示類C是由類A和類B混合而構(gòu)成
class C = A with B;
main() {
C c = new C();
c.a(); // A's a()
c.b(); // B's b()
}
靜態(tài)成員變量和靜態(tài)成員方法
// 類的靜態(tài)成員變量和靜態(tài)成員方法
class Cons {
static const name = "zhangsan";
static sayHello() {
print("hello, this is ${Cons.name}");
}
}
main() {
Cons.sayHello(); // hello, this is zhangsan
print(Cons.name); // zhangsan
}
泛型(Generics)
Java和C++語言都有泛型外遇,Dart語言也不例外,使用泛型有很多好處契吉,比如:
正確指定泛型類型會產(chǎn)生更好的生成代碼臀规。
泛型可以減小代碼的復(fù)雜度
Dart內(nèi)置的數(shù)據(jù)類型List就是一個(gè)泛型數(shù)據(jù)類型,你可以往List中塞任何你想的數(shù)據(jù)類型比如整型栅隐、字符串塔嬉、布爾值等
關(guān)于Dart更多的泛型知識點(diǎn),可以查看這里租悄。
Dart庫(Libraries)
Dart目前已經(jīng)有很多的庫提供給開發(fā)者谨究,許多功能不需要開發(fā)者自己去實(shí)現(xiàn),只需要導(dǎo)入對應(yīng)的包即可泣棋,使用import語句來導(dǎo)入某個(gè)包胶哲,比如下面的代碼:
import 'dart:html';
如果你想導(dǎo)入自己寫的某個(gè)代碼文件,使用相對路徑即可潭辈,例如當(dāng)前有一個(gè)demo.dart文件鸯屿,跟該文件同級目錄下有個(gè)util.dart文件澈吨,文件代碼如下:
// util.dart文件內(nèi)容
int add(int a, int b) {
return a + b;
}
在demo.dart文件中如果要引用util.dart文件,使用下面的方式導(dǎo)入:
// demo.dart
import './util.dart';
main() {
print(add(1, 2));
}
你可以使用as關(guān)鍵字為導(dǎo)入的某個(gè)包設(shè)置一個(gè)前綴寄摆,或者說別名谅辣,比如下面的代碼:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
你也可以在導(dǎo)入包時(shí)使用show hide關(guān)鍵字來導(dǎo)入某個(gè)包中的部分功能,比如下面的代碼:
// 只導(dǎo)入foo
import 'package:lib1/lib1.dart' show foo;
// 導(dǎo)入除了foo的所有其他部分
import 'package:lib2/lib2.dart' hide foo;
導(dǎo)入包時(shí)使用deferred as可以讓這個(gè)包懶加載婶恼,懶加載的包只會在該包被使用時(shí)得到加載桑阶,而不是一開始就加載,比如下面的代碼:
import 'package:greetings/hello.dart' deferred as hello;
異步
Dart提供了類似ES7中的async await等異步操作勾邦,這種異步操作在Flutter開發(fā)中會經(jīng)常遇到蚣录,比如網(wǎng)絡(luò)或其他IO操作,文件選擇等都需要用到異步的知識眷篇。
async和await往往是成對出現(xiàn)的萎河,如果一個(gè)方法中有耗時(shí)的操作,你需要將這個(gè)方法設(shè)置成async蕉饼,并給其中的耗時(shí)操作加上await關(guān)鍵字公壤,如果這個(gè)方法有返回值,你需要將返回值塞到Future中并返回椎椰,如下代碼所示:
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
下面的代碼使用Dart從網(wǎng)絡(luò)獲取數(shù)據(jù)并打印出來:
import 'dart:async';
import 'package:http/http.dart' as http;
Future<String> getNetData() async{
http.Response res = await http.get("http://www.baidu.com");
return res.body;
}
main() {
getNetData().then((str) {
print(str);
});
}
dart簡易教程 - 吳先鋒Flutter的文章 - 知乎
https://zhuanlan.zhihu.com/p/57163557