最近和移動小夥伴一起重新學習 Dart ,主要是看 CoderWhy 視訊教程 講得挺不錯的,順便做了個筆記
變數宣告
/*************** 宣告變數 ******************/
void defineVariable() {
// 變數宣告(var/final/const)
// var 宣告變數
var age = 20;
// age = "abc";
age = 30;
// final宣告常量
final height = 1.88;
// const宣告常量
const address = "深圳市";
// final和const的區別
// const date1 = DateTime.now(); 寫法錯誤
final date2 = DateTime.now();
// ? 在Dart 2.0 之後, const可以省略
const p1 = const Person("hello");
const p2 = const Person("world");
const p3 = const Person("zhengzeqin");
print(identical(p1, p2)); // true
print(identical(p2, p3)); // false
// ? 在Dart 2.12 之後, 預設可選型別需要加 ? 以前預設不加
String? optionName = null;
optionName = "zhengzeqin";
}
複製程式碼
final 和 const 的區別
- const 必須賦值常量值(編譯期間需要有一個確定的值)
- final 可以通過計算/函式獲取一個值(執行期間來確定一個值)
runtimeType
runtimeType
: 用於獲取變數當前的型別
var name = 'zhengzeqin';
print(name.runtimeType); // String
複製程式碼
dynamic的使用
類似 swift Any 宣告動態變數
question
dynamic 與 Object 區別?
// 知識點: Object和dynamic的區別
// 父類應用指向子類物件
// Object和dynamic
// Object呼叫方法時, 編譯時會報錯
// dynamic呼叫方法時, 編譯時不報錯, 但是執行時會存在安全隱患
// 錯誤示例
Object obj = "why";
print(obj.substring(1));
// 明確宣告
dynamic obj2 = 123;
print(obj2.substring(1));
複製程式碼
identical
判斷兩個變數型別是否一致 補充:const 修飾的常量物件,建立是同一個物件(共享物件),注意類需要定義 const 建構函式
// 在Dart2.0之後, const可以省略
const p1 = const Person("hello");
const p2 = const Person("world");
const p3 = const Person("zhengzeqin");
print(identical(p1, p2)); // true
print(identical(p2, p3)); // false
class Person {
final String name;
const Person(this.name);
}
複製程式碼
資料型別
數字型別
int double
字串
/*************** 字串 ******************/
void stringFunction() {
// 1.定義字串的方式
var s1 = 'Hello World';
var s2 = "Hello Dart";
var s3 = 'Hello\'Fullter';
var s4 = "Hello'Fullter";
// 2.表示多行字串的方式
var message1 = '''
哈哈哈
呵呵呵
嘿嘿嘿''';
print('my name is ${message1}');
// 3.拼接其他變數
var name = 'zhengzeqin';
var age = 18;
var height = 1.88;
print('my name is ${name}, age is $age, height is $height');
}
複製程式碼
布林型別
不存在非零即真
dart 宣告變數不存在非零即真情況
var flag = "abc";
if (flag) { // 錯誤示例
print("執行程式碼");
}
複製程式碼
字串
- 支援 "", '', """ """ 三種方式
- """ """ 支援換行
- 強調: ${變數}, 那麼{}可以省略,如果是函式或者表示式計算則需要不可以省略
// 字串
void stringFunction() {
// 1.定義字串的方式
var s1 = 'Hello World';
var s2 = "Hello Dart";
var s3 = 'Hello\'Fullter';
var s4 = "Hello'Fullter";
// 2.表示多行字串的方式
var message1 = '''
哈哈哈
呵呵呵
嘿嘿嘿''';
print('my name is ${message1}');
// 3.拼接其他變數
var name = 'zhengzeqin';
var age = 18;
var height = 1.88;
print('my name is ${name}, age is $age, height is $height');
}
複製程式碼
集合
Dart則內建了最常用的三種:List / Set / Map
- Set和List最大的兩個不同就是:Set是無序的,並且元素是不重複的。
void collectFunction() {
// List定義
// 1.使用型別推導定義
var letters = ['a', 'b', 'c', 'd'];
print('$letters ${letters.runtimeType}');
// 2.明確指定型別
List<int> numbers = [1, 2, 3, 4];
print('$numbers ${numbers.runtimeType}');
// Set的定義 Set和List最大的兩個不同就是:Set是無序的,並且元素是不重複的。
// 1.使用型別推導定義
var lettersSet = {'a', 'b', 'c', 'd'};
print('$lettersSet ${lettersSet.runtimeType}');
// 2.明確指定型別
Set<int> numbersSet = {1, 2, 3, 4};
print('$numbersSet ${numbersSet.runtimeType}');
numbers = Set<int>.from(numbers).toList();
print(numbers);
// 新增/刪除/包含元素
numbers.add(5);
numbersSet.add(5);
print('$numbers $numbersSet');
numbers.remove(1);
numbersSet.remove(1);
print('$numbers $numbersSet');
print(numbers.contains(2));
print(numbersSet.contains(2));
// List根據index刪除元素
numbers.removeAt(3);
print('$numbers');
// Map的定義
// 1.使用型別推導定義
var infoMap1 = {'name': 'harden', 'age': 18};
print('$infoMap1 ${infoMap1.runtimeType}');
// 2.明確指定型別
Map<String, Object> infoMap2 = {'height': 1.88, 'address': '深圳市'};
print('$infoMap2 ${infoMap2.runtimeType}');
// Map的操作
// 1.根據key獲取value
print(infoMap1['name']); // harden
// 2.獲取所有的entries
print('${infoMap1.entries} ${infoMap1.entries.runtimeType}'); // (MapEntry(name: why), MapEntry(age: 18)) MappedIterable<String, MapEntry<String, Object>>
// 3.獲取所有的keys
print('${infoMap1.keys} ${infoMap1.keys.runtimeType}'); // (name, age) _CompactIterable<String>
// 4.獲取所有的values
print('${infoMap1.values} ${infoMap1.values.runtimeType}'); // (harden, 18) _CompactIterable<Object>
// 5.判斷是否包含某個key或者value
print('${infoMap1.containsKey('age')} ${infoMap1.containsValue(18)}'); // true true
// 6.根據key刪除元素
infoMap1.remove('age');
print('${infoMap1}'); // {name: harden}
}
複製程式碼
question
- 下面寫法有錯嗎?
var info<String, Object> = {
"name": "why",
"age": 18
};
複製程式碼
- var names = ["abc", "cba", "nba", "cba"]; 這個如果需要指定型別怎麼寫呢?
函式
返回值 函式的名稱(引數列表) {
函式體
return 返回值
}
複製程式碼
可選引數
可選引數可以分為 命名可選引數 和 位置可選引數
- ? 位置可選引數:對應的順序不可以錯
- dart 中沒有函式的過載
命名可選引數: {param1, param2, ...}
位置可選引數: [param1, param2, ...]
// 可選引數: 位置可選引數 - 命名可選引數
// 注意: 只有可選引數才可以有預設值
// 位置可選引數: [int age, double height]
// 實參和形參在進行匹配時, 是根據位置的匹配
void sayHello1(String name, [int age = 10, double height = 2, int money = 0]) {
print("sayHello1 name: $name age: $age age: $height money: $money");
}
// 命名可選引數
void sayHello2(String name, {int age = 10, double height = 3.14}) {
print("sayHello2 name: $name age: $age age: $height");
}
複製程式碼
question
位置可選引數可選引數,一定要按順序才能傳參嗎?如果只想傳 money 引數,不想傳其他引數怎麼辦呢?
函式是一等公民
可以將函式賦值給一個變數, 也可以將函式作為另外一個函式的引數或者返回值來使用
void firstFunction() {
// 1.直接找到另外一個定義的函式傳進去
// test(bar);
// 2.匿名函式 (引數列表) {函式體};
translationFunc(() {
print("匿名函式被呼叫");
return 10;
});
var movies = ['無間道1', '無間道2', '無間道3'];
// 使用forEach遍歷: 有名字的函式
printElement(item) {
print(item);
}
movies.forEach(printElement);
// 使用forEach遍歷: 匿名函式
movies.forEach((item) {
print(item);
});
movies.forEach((item) => print(item));
// 3.箭頭函式: 條件, 函式體只有一行程式碼
translationFunc(() => print("箭頭函式被執行"));
// 4. 使用別名定義引數 要求: 傳入一個函式 & 匿名函式
calculateFunc((num1, num2) {
return num1 * num2;
});
// 5. 宣告函式,呼叫
var add = addFunc();
print(add(20, 30));
}
// 函式可以作為另外一個函式的引數
void translationFunc(Function foo) {
foo();
}
void bar() {
print("bar函式被呼叫");
}
// 使用別名定義函式型別
typedef Calculate = int Function(int num1, int num2);
void calculateFunc(Calculate calc) {
calc(20, 30);
}
Calculate addFunc() {
return (num1, num2) {
return num1 * num2;
};
}
複製程式碼
question
箭頭函式支援多行嗎?
運算子
條件
??=
: 當變數為null
時,使用後面的內容進行賦值,否則不賦值??
: 當變數為null
時,則使用後面的值,否則使用變數的值
void conditionalOperatorFunc() {
// 1.??=:
// 當原來的變數有值時, 那麼??=不執行
// 原來的變數為null, 那麼將值賦值給這個變數
var name = null;
name ??= "harden";
print(name);
// ??:
// ??前面的資料有值, 那麼就使用??前面的資料
// ??前面的資料為null, 那麼就使用後面的值
var name2 = null;
var temp = name2 ?? "harden";
print(temp);
}
複製程式碼
級聯
...
: 類似鏈式呼叫
class Animal {
String? name;
Animal(this.name);
void run() {
print("running");
}
void eat() {
print("eating");
}
}
// 級聯運算子
void cascadeOperatorFunc() {
// 級聯運算子
var p = Animal("zhengzeqin")
..name = "harden"
..eat()
..run();
}
複製程式碼
流程控制
if else
for
while
do-while
break
continue
switch-case
複製程式碼
void processControlFunc() {
for (var i = 0; i < 5; i++) {
print(i);
}
var names = ['harden', 'kobe', 'curry'];
for (var name in names) {
print(name);
}
var direction = 'east';
switch (direction) {
case 'east':
print('東面');
break;
case 'south':
print('南面');
break;
case 'west':
print('西面');
break;
case 'north':
print('北面');
break;
default:
print('其他方向');
}
}
複製程式碼
類和物件
構造方法
- 當類中沒有明確指定構造方法時,將預設擁有一個無參的構造方法。
- ? 在Dart 2.12 之後, 預設可選型別需要加 ? 以前預設不加 否則預設的無參建構函式不能編譯通過
- ? 當有了自己的構造方法時,預設的構造方法將會失效,不能使用
- 當然,你可能希望明確的寫一個預設的構造方法,但是會和我們自定義的構造方法衝突;
- 這是因為Dart本身 不支援函式的過載(名稱相同, 引數不同的方式)
- 命名構造方法:自定義命名的建構函式
- 初始化列表:建構函式體執行之前初始化例項變數,可以使用初始化列表
- 重定向構造方法:希望在一個構造方法中去呼叫另外一個構造方法, 這個時候可以使用重定向構造方法
- 常量構造方法:傳入相同值時,我們希望返回同一個物件,這個時候,可以使用常量構造方法 參考 final 部分
- 工廠構造方法:Dart 提供了 factory 關鍵字, 用於通過工廠去獲取物件
void classFunc() {
var hunman = Human(12);
print("hunman: $hunman");
}
class Runner {
// ? 在Dart 2.12 之後, 預設可選型別需要加 ? 以前預設不加 否則預設的無參建構函式不能編譯通過
String? name;
int? age;
}
class Human {
// ? 在Dart 2.12 之後, 預設可選型別需要加 ? 以前預設不加 否則預設的無參建構函式不能編譯通過
String? name;
int? age;
// Human(String name, int age) {
// this.name = name;
// this.age = age;
// }
// ? 預設是無慘建構函式,宣告引數建構函式,則系統預設無參建構函式就不存在
// Human(this.name, this.age); // 語法糖等同註釋部分
// 初始化列表頁
Human(this.age) : name = "zhengzeqin age is $age";
// 命名構造方法
Human.withArgments(String name, int age) {
this.name = name;
this.age = age;
}
// 命名一個重定向建構函式
Human.form(int age) : this(age);
// 常量構造方法
// 工程構造方法, ? 如果存在了同名建構函式,則無法再實現工廠建構函式
// factory Human(Int age) {
// return Human.withArgments("zhengzeqin", age);
// }
// setter && getter
String? get getName {
return name;
}
set setName(String name) {
this.name = name;
}
@override
String toString() {
return 'name=$name age=$age';
}
}
複製程式碼
抽象類
- 抽象方法,必須存在於抽象類中
- 抽象類是使用abstract宣告的類
- ? 如果有實現體,實現的類可以不實現該抽象方法
// 抽象類
abstract class Shape {
double getArea();
// ? 如果有實現體,實現的類可以不實現該抽象方法
void getName() {}
}
class Circle extends Shape {
double? r;
Circle(this.r);
@override
getArea() {
final rr = r ?? 0;
return rr * rr * 3.14;
}
}
class Reactangle extends Shape {
double w = 0;
double h = 0;
Reactangle(this.w, this.h);
@override
getArea() {
return w * h;
}
}
複製程式碼
隱式介面
- Dart 中的介面比較特殊, 沒有一個專門的關鍵字來宣告介面.
- 預設情況下,定義的每個類都相當於預設也宣告瞭一個介面,可以由其他的類來實現(因為Dart不支援多繼承)
- 通過extends 繼承類,而 implements 來實現介面
abstract class Player {
play();
}
abstract class Flyer {
fly();
}
class SuperManer implements Player, Flyer {
@override
play() {
print('超人在玩');
}
@override
fly() {
print('超人在飛');
}
}
複製程式碼
Mixin
- 除了可以通過 class 定義類之外,也可以通過 mixin 關鍵字來定義一個類。
- 只是通過 mixin 定義的類用於被其他類混入使用,通過 with 關鍵字來進行混入,等同於多繼承
// implements 的方式要求必須對其中的方法進行重新實現, with 則不需要
// 使用 with 方式混入 mixin 類,等同多繼承
// on 關鍵字限定指定類的子類可以使用當前混入(不加預設限定為 Object)
mixin Runing {
var name = "";
run() {
print('在奔跑');
}
}
mixin Flying {
fly() {
print('在飛翔');
}
}
class SuperWoman with Flying, Runing {
void sayHello() {
print("hello my name is $name");
}
}
複製程式碼
泛型
List和Map的泛型
使用者希望使用的是 int 型別,還是double型別, 甚至是一個字串, 這個時候如何定義呢?
- 一種方案是使用Object, dynamic 型別, 但是在之後使用時, 非常不方便
- 另一種方案就是使用泛型.
void genericFunc() {
// 限制型別
var names1 = <String>['harden', 'kobe', 'james'];
List<String> names2 = ['harden', 'kobe', 'james'];
// 對型別進行顯示
Map<String, dynamic> infos1 = {'name': 'harden', 'age': 18};
var infos2 = <String, dynamic>{'name': 'harden', 'age': 18};
}
// 指定 T 是繼承 num 類
class Location<T extends num> {
T x;
T y;
Location(this.x, this.y);
}
複製程式碼
庫的使用
- import '庫所在的url';
- dart: 字首表示Dart的標準庫,如 dart:io、dart:html、dart:mathimport 'dart:io';
- 當然,你也可以用相對路徑或絕對路徑的 dart 檔案來引用 import 'lib/student/student.dart';
- 庫中內容和當前檔案中的名字衝突使用 as 起名稱空間作用 import 'lib/student/student.dart' as Stu;
- 如果希望只匯入庫中某些內容,或者刻意隱藏庫裡面某些內容,可以使用show和hide關鍵字
- import 'lib/student/student.dart' show Student, Person;
- import 'lib/student/student.dart' hide Person;
export
- 通過 export 匯入多個庫
代理示例
- 傳送門