最近和移动小伙伴一起重新学习 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
};
```
> 2. var names = ["abc", "cba", "nba", "cba"]; 这个如果需要指定类型怎么写呢?
## 函数
```dart
返回值 函数的名称(参数列表) {
函数体
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;
}
String toString() {
return 'name=$name age=$age';
}
}
抽象类
- 抽象方法,必须存在于抽象类中
- 抽象类是使用abstract声明的类
- 📢 如果有实现体,实现的类可以不实现该抽象方法
// 抽象类
abstract class Shape {
double getArea();
// 📢 如果有实现体,实现的类可以不实现该抽象方法
void getName() {}
}
class Circle extends Shape {
double? r;
Circle(this.r);
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);
getArea() {
return w * h;
}
}
隐式接口
- Dart 中的接口比较特殊, 没有一个专门的关键字来声明接口.
- 默认情况下,定义的每个类都相当于默认也声明了一个接口,可以由其他的类来实现(因为Dart不支持多继承)
- 通过extends 继承类,而 implements 来实现接口
abstract class Player {
play();
}
abstract class Flyer {
fly();
}
class SuperManer implements Player, Flyer {
play() {
print('超人在玩');
}
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 导入多个库
代码示例
- 传送门
参考
Thanks
- 本文链接:https://zhengzeqin.netlify.app/2021/07/30/02-03-Dart%E8%AF%AD%E6%B3%95%E7%B2%BE%E8%AE%B2-%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues