Dart 学习笔记

字符串

多行字符串

  String str1 = """
  你好
  dart
  """;
  print(str1);

字符串拼接

  String str2 = "你好";
  String str3 = "dart";

  print("$str2 $str3");

列表

指定类型创建

var l1=<String>["1","2"]
var l2=<int>[1,2,3];

移除 new List()

新版本不支持 new 创建列表

List.filled 创建固定长度列表

// 创建长度是 5,每个元素的值是 0 的列表,并自动推导为 int 类型
// 不可以增加元素
var l1= List.filled(5,0);

// 不可以修改长度
// l1.length = 0;

List.filled 指定类型创建列表

var l1= List<String>.filled(5,"你好");

字典

创建和获取

// 字面量方式直接创建
  var m1 = {
    "name": "dc",
    "age": 30
  };
  // 中括号方式取值,不区分双引号 还是单引号
  print(m1['name']);
  print(m1["name"]);
  // 不支持用 .name 的方式
  // print(m1.name); 报错

通过 new Map() 创建

  var m1 = new Map();
  m1["name"] = "dc";
  m1["age"] = 28;

is 类型判断

  var m1 = 345;
  if(m1 is int) {
    print("int");
  }else if (m1 is String) {
    print("String");
  }

算术运算符

取整 ~/

  var m1 = 5;
  print(m1 / 3); // 1.666666
  print(m1 ~/ 3); // 1

赋值运算符

??=

a ??= b 如果 a 等于空, 将 b 的值赋予 a

  var m1;
  m1 ??= 5;
  print(m1); // 5

  var m2 = 6;
  // m2 不等于空, 不会赋值
  m2 ??= 5;
  print(m2); // 6

??

a = b ?? c 如果 b 等于空,把 c 的值赋给 a

  var m1;
  var m2;
  m1 = m2 ??  5;
  print(m1);

类型转换

字符串转 int

int.parse

  var m = "123";
  var m2 = int.parse(m);
  print(m2 is int); // true
  print(m2); // 123

字符串转 double

double.parse

  var m = "123.2";
  var m2 = double.parse(m);
  print(m2 is double);
  print(m2);

转 String

toString

空比较

  var m;
  // 不会报错,空值可以比较
  print(m == 0); // false
  print(m == null); // true

NaN

  var m = 0 / 0;
  // 不会报错
  print(m); // Nan
  print(m.isNaN); // true

方法

嵌套

void pa() {
  print("a");
  // 嵌套方法,作用在 pa() 内部
  void pb() {
    print("b");
  }
  pb();
}

void main() {
  pa();
  // 报错,超出作用域
  pb();
}

省略返回类型,不建议

// 如果不知道方法的返回类型可以不写,但是建议写上
pa() {
  return 3;
}
void main() {
  print(pa());
}

可选参数

// 可选参数用 [] 包裹,并且允许为空
void pa(String name, [int ? age, String ? address]) {
  print("name: $name");
  if (age != null) {
    print("age: $age");
  }else{
    print("age 未知");
  }

  if (address != null) {
    print("address: $address");
  }else{
    print("address 未知");
  }
}

void main() {
  pa("张三", 30);
  // name: 张三
  // age: 30
  // address 未知
}

默认参数

定义方法时,给可选参数设置默认值

void pa(String name, [int ? age, String address= "北京"]) {
  print("name: $name");
  if (age != null) {
    print("age: $age");
  }else{
    print("age 未知");
  }

  if (address != null) {
    print("address: $address");
  }else{
    print("address 未知");
  }
}

void main() {
  pa("张三");
}

输出:

name: 张三
age 未知
address: 北京

命名参数

// 命名参数,用{} 包裹,可以指定参数名赋值,而不按照顺序
void pa(String name, {int ? age, String ? address}) {
  print("name: $name");
  if (age != null) {
    print("age: $age");
  }else{
    print("age 未知");
  }

  if (address != null) {
    print("address: $address");
  }else{
    print("address 未知");
  }
}

void main() {
  // 命名参数可以跳过 age , 指定 address 的值
  pa("张三", address: "上海");
  // 可选参数,只能按照顺序赋值
}

方法作为参数传入

void fn1(){
  print("fn1");
}

void fn2(){
  print("fn2");
}

// 参数是个方法
void f3(fn){
  // 调用传入的方法
  fn();
  print("fn3");
}

void main() {
  f3(fn1);
  f3(fn2);
}

输出:

fn1
fn3
fn2
fn3

访问属性的三种方法

推荐使用 this 访问

class Person{
  int age = 10;
  String name = "张三";

  void out(){
    print("$name: $age 岁");
    print("${name}: ${age} 岁");
    // 推荐
    print("${this.name}: ${this.age} 岁");
  }
}

默认构造方法的简写形式

默认构造方法只能有一个

class Person {
  int age;
  String name;

  // 构造方法
  // Person(int age, String name) {
  //   this.age = age;
  //  this.name = name;
  // }

  // 构造方法的简写形式
  Person(this.age, this.name);

  void getInfo() {
    print("${this.name}: ${this.age} 岁");
  }
}

void main() {
  Person p1 = new Person(10, "张三");
  p1.getInfo();
}

命名构造方法

命名构造方法可以有多个

class Person {
  int age = 0;
  String name = "";

  // 默认构造方法的简写形式
  // 只能有一个
  Person(this.age, this.name);

  // 命名构造方法
  // 可以有多个
  Person.one(int age){
    this.age = age;
    this.name = "李四";
  }

  // 命名构造方法的简写形式
  Person.two(this.age){
    this.name = "王二";
  }

  void getInfo() {
    print("${this.name}: ${this.age} 岁");
  }
}

void main() {
  Person p1 = Person.one(20);
  p1.getInfo();

  Person p2 = Person.two(30);
  p2.getInfo();
}

导入

lib/Person.dart

class Person {
  int _age = 0;
  String _name = "";

  Person(this._age, this._name);

  Person.one(int age){
    this._age = age;
    this._name = "李四";
  }

  void getInfo() {
    print("${this._name}: ${this._age} 岁");
  }
}

main.dart

// 导入同目录下的类
import 'lib/Person.dart';
void main() {
  Person p1 = Person.one(20);
  p1.getInfo();
}

重命名包

如果要导入的包有相同的类名,可以使用 as xx, 将该包重命名为 xx 使用时带上前缀:xx.Class
如下

import 'lib/Person1.dart';
import 'lib/Person2.dart' as lib;

void main() {
  Person p = new Person("dc1", 10);
  p.getInfo();

  lib.Person p2 = new lib.Person("dc2", 10);
  p2.getInfo();
}

部分引入

  • 只导入需要的部分
  • 隐藏不需要的部分

Tools.dart

void getName() {
  print("get name");
}

void getAge() {
  print("get age");
}

void cal() {
  print("cal");
}

main.dart

// 只引入 getAge() cal() 方法
import 'lib/Tools.dart' show getAge, cal;

void main() {
  cal();
  getAge();
}
// 隐藏 cal() 方法
import 'lib/Tools.dart' hide  cal;

void main() {
  getAge();
  getName();
}

私有属性 私有方法

下划线开头的属性和方法是私有的,只能在当前类中访问

class Person {
  // 下划线开头的属性是私有属性,类外文件无法访问到
  int _age = 0;
  String _name = "";

  Person(this._age, this._name);

  Person.one(int age){
    this._age = age;
    this._name = "李四";
  }
  
  _run(){

  }

  void getInfo() {
    print("${this._name}: ${this._age} 岁");
  }
}

getter 和 setter

class Person {
  int _age = 0;

  // getter
  get getAge {
    return _age;
  }

  // setter
  set setAge(int age) {
    this._age = age;
  }
}

main.dart

import 'lib/Person.dart';

void main() {
  Person p1 = new Person();
  // 给私有成员赋值
  p1.setAge = 10;
  // 获取私有成员的值
  print(p1.getAge);
}

对象运算符

? 条件运算符

import 'lib/Person.dart';

void main() {
  Person? p;
  // 如果 p 等于空,则不调用 getInfo 方法
  p?.getInfo();  // Nothing

  Person? p1 = new Person("dc1", 20);

  // p1 不等于空,会调用 getInfo 方法
  p1?.getInfo();
}

is 类型判断

import 'lib/Person.dart';

void main() {
  Person p = new Person("dc", 20);
  print( p is Person) // true
}

as 类型转换

import 'lib/Person.dart';

void main() {
  var p;
  p = new Person("dc", 20);
  (p as Person).getInfo();
}

.. 连缀

import 'lib/Person.dart';

void main() {
  Person p = Person.empty();
  p
    ..name = "dc10"
    ..age = 10
    ..getInfo();

  // 等同于
  // p.name = "dc10";
  // p.age = 10;
  // p.getInfo();
}

继承中的超级初始化器

class Animal {
  String? name;
  int? age;

  Animal(String this.name, int this.age);

  void printInfo() {
    print("${name}: ${age}");
  }
}

class Cat extends Animal {
  // 超级初始化器
  // 因为子类的构造方法中必须在第一行调用父类的构造方法,dart 直接将这以规则提升到语法层面。防止忘记
  Cat(String name, int age) : super('', 0);
}

void main() {
  Cat cat = new Cat("jonn", 2);
  cat.printInfo();
}

mixin 混入

mixin A 关键词允许 A 类混入其他类中

class C with A C 具有 A 的所有 public 的方法

  • 实现了多继承的效果
  • A 不能有构造方法
mixin class A {
  String? aName;

  // 不能有构造方法
  // A(){}

  void printA() {
    print(aName);
  }

  void _printA1() {
    print("私有方法");
  }
}

mixin B {
  String? bName;

  void printB() {
    print(bName);
  }
}

// 不可以混入其他类中
class B1 {
}

class C with A, B {
  String? cName;

  void printC() {
    print(cName);
  }
}

void main() {
  C c = new C();

  c.aName = "a";
  c.bName = "b";
  c.cName = "c";

  c.printA();
  c.printB();
  c.printC();

  print(c is A); // true
  print(c is B); // true
}

依赖

1. 依赖说明文件

根目录下 pubspec.yaml

2. 依赖声明

# 项目名称
name: study01
# 指定 sdk
environment:
  sdk: "^3.5.0"
# 指定依赖版本
dependencies:
  http: ^1.2.2
  dio: ^5.7.0

3. 安装依赖

dart pub get

4. 用命令的方式安装依赖

dart pub add http

deps

用于显示当前 Package 使用的所有依赖项。

空安全,延迟初始化,参数不能为空

class Person {
  // name 可以为空
  String? name;

  // 初始化对象时,sex 可以暂时为空,但在使用时,它不能为空
  late String sex;

  // age 不允许为空,也不可以延迟赋值
  // 初始化对象时,age 必须有值
  int age;

  // age 不允许为空,所以在构造函数中要有 required 关键词,否则编译报错
  // set 不允许为空,但可以延迟初始化,所以在构造函数中,可以不对 sex 赋值
  // name 可以为空,所以不用加 required
  Person({required this.age, this.name});

  void setSex(String sex) {
    this.sex = sex;
  }

  void getInfo() {
    print("姓名:${this.name}");
    print("年龄:${this.age}");
    print("性别:${this.sex}");
  }
}

void main() {
  Person p = Person(age: 10);
  // 在使用 sex 之前必须赋值,否则运行报错
  p.setSex("sex");
  p.getInfo();
}

常量

const 和 final

  • const 是编译时常量, final 是运行时常量
  • const 在声明变量时就要赋值,final 允许延迟赋值。
  • 均只能赋值一次
void main() {
  // final 声明的常量可以在运行时赋值,但只能赋值一次
  final int a;
  a = 1;
  // 再次赋值会报错
  // a = 2;

  // const 声明的常量,在声明时就要赋值
  const int b = 1;
  // 不可以改变
  // b = 2;
}

节省内存

被 const 修饰的构造函数,参数一样时,多次构造出来的对象占用同一个内存空间

identical(a,b) 判断 a b 的内存地址是否一样

class Person {
  // 字段不可变
  final int age;

  // 常量构造函数,使用时才可以被 const 修饰
  const Person(this.age);
}

void main() {
  // 被 const 修饰的构造函数,参数一样时,构造出来的对象占用同一个内存空间
  var p1 = const Person(10);
  var p2 = const Person(10);
  var p3 = const Person(20);
  print(identical(p1, p2)); // true
  print(identical(p1, p3)); //false
}

联系方式:dccmmtop@foxmail.com