Dart:补充

前言

前面那几篇Dart文章,写的很基础,是我初学时根据教程简单记录的。这篇文章主要用来对前面内容进行补充,会随着学习不断扩展。

特殊运算符

??=

??= 是空值赋值运算符,当变量是空值时才会进行赋值操作

示例

  var b = null;
  b ??= 2;
  print("b可能为空值,b的值是${b}"); //2

注: 这里的空值指的是null

??

?? 可以理解为三元运算符的简写

示例

  var a = null;
  var b = a ?? 'aaa';
  print(b); // aaa

  //等价于
  var c = a != null ? a : 'aaa';
  print(c); // aaa

注: 不要跟js混了,js中直接会对null进行类型转换

..

.. 是级联运算符

示例

main() {
    
    
  var p1 = Person();
  p1.name = 'p1';
  p1.run();

  //等价于
  var p2 = Person()
    ..name = 'p2'
    ..run();
}

class Person {
    
    
  String name = '';

  run() {
    
    
    print("${this.name}正在跑!");
  }
}

在这里插入图片描述

循环

for in

main() {
    
    
  List<String> nameList = ['张三', '李四'];

  for (var name in nameList) {
    
    
    print(name);
  }
}

dynamic、var、object 三种类型的区别

dynamic 表示是动态的,数据类型是指任意类型。通过它定义的变量编译时会关闭类型检查,这会导致运行时有可能会出错。在开发中不要直接使用它

var 可以理解为我不关心这个变量是什么类型,编译时系统会自动进行推断。

object:是Dart 对象的基类,当你定义: object a = 123;时这个时候系统会认为a是个对象,你可以调用a的toString()和hashCode()方法,因为Object 提供了这些方法,但是如果你尝试调用a的substring方法时,静态类型检查会运行报错。

初始化列表

一般在使用可选参数时会用到,例如下面的代码,age是可选参数,虽然在类中已经初始化了age,但是这样是不允许的。
在这里插入图片描述

正确写法
在这里插入图片描述
最开始是这样的

 Person(this.name, {
    
    int age}) : this.age = age ?? 10 {
    
    }

但是一直提示错误,后来才想起来 dart 2.17版本使用可选参数时要么一开始就赋值,比如 {int age = 10} ,要么就加一个问号 {int? age}

构造函数重定向

main() {
    
    
  var p1 = Person("p1");
  print(p1.age); //0
}

class Person {
    
    
  String name;
  int age;

//构造函数重定向
  Person(String name) : this._internal(name, 0);

  Person._internal(this.name, this.age);
}

常量构造函数

常量构造函数可以保证创建出来的对象是一个(构造函数的值必须是一样的)

普通构造函数

main() {
    
    
  var p1 = Person("a");
  var p2 = Person('a');

  var result = identical(p1, p2);

  print("p1和p2对应的对象是一个:${result}"); //false
}

class Person {
    
    
  String name;
  Person(this.name);
}

常量构造函数

main() {
    
    
  const p1 = Person("a");
  const p2 = Person('a');

  var result = identical(p1, p2);

  print("p1和p2对应的对象是一个:${result}"); //true
}

class Person {
    
    
  final String name;
  const Person(this.name);
}

注意点:
1、如果是普通构造函数,那么 const p1 = Person("a"); 是错误的,会提示构造函数不是常量构造函数;
如果是常量构造函数,那么 const p1 = Person("a");var p1 = Person("a"); 都是可以的,但是只有都是用const 定义的对象,其 对象才指向同一个内存。
`
2、类中只能有一个常量构造函数

3、构造函数如果是常量构造函数,那么类中不允许出现变量
在这里插入图片描述

工厂构造函数

dart中用factory 修饰的构造函数是工厂构造函数。图片构造函数会默认返回创建的对象,而工厂构造函数,需要手动通过return 返回创建的对象。

示例:

/// 工厂构造函数,
/// 也叫 “单例模式”,是设计模式的一种,是面向对象很重要的一种设计模式,
/// 一个程序无论实例化多少类,工厂构造函数只返回第一次实例化的对象,这样
/// 就会节约许多计算机资源。普通构造函数每次实例化类的时候,就会开辟一段
/// 内存来存放实例化对象资源。
class Person {
    
    
  String name;

  // 静态属性存放实例化对象
  static var instance;

  //工厂构造函数
  factory Person([String name = "刘备"]) {
    
    
    // 工厂构造函数不能使用 this 关键字
    Person.instance ??= new Person.newSelf(name);
    return Person.instance;
  }

  Person.newSelf(this.name);
}

void main() {
    
    
  var p1 = new Person('关羽');
  print(p1.name);

  var p2 = new Person('张飞');
  print(p2.name);

  var p3 = new Person('诸葛亮');
  print(p3.name);

  // 判断两次实例化的对象是否一致。
  print(p1 == p2);
  print(p1 == p3);
}

抽象类的实例化

参考:Dart - 抽象类的实例化 ,这篇文章讲的很清楚可以看一下。
虽然前面说了抽象类不能够进行实例化,但是抽象类可以借助工厂函数来实现抽象化。典型的例子就是Map,进入到Map 我们可以看到

void main() {
    
    
  var a = Map();
}

在这里插入图片描述

原因就是:工厂方法可以返回一个实例对象,但这个对象的类型不一定就是当前类
打印一下Map对象的运行时类型,可以看到是 _InternalLinkedHashMap
在这里插入图片描述

external 和 @patch

external 可以分离方法的声明与实现
@patch 关联某个类中用 external 修饰的方法的实现

示例

void main() {
    
    
  var a = Animal();

  print(a.runtimeType);
}

abstract class Animal {
    
    
  void eat();

  void sleep() {
    
    
    print("睡觉");
  }

  factory Animal() {
    
    
    return Cat();
  }
}

class Cat implements Animal {
    
    
  void eat() {
    
    
    print("吃");
  }

  void sleep() {
    
    
    print('睡');
  }
}

注: 只能使用 implements ,不能使用 extends。在抽象类中定义了工厂构造方法后,在子类中不能定义除工厂构造方法外的其它构造方法了,会报错。
在这里插入图片描述

好处: 复用同一套API的声明,可以针对不同的平台做不同的实现

utils.dart

int sum(int a, int b) {
    
    
  return a + b;
}

int multiply(int a, int b) {
    
    
  return a * b;
}

库的重命名

当我们导入库中的某个方法和当前文件中的某个方法重名时,我们可以通过 as 来起个别名。
例如:

import './utils.dart' as Utils;

void main() {
    
    
  print(Utils.sum(1, 2));
}

void sum(int a, int b) {
    
    
  print(a + b);
}

show 和 hide

默认情况下导入一个库时,会导入所有的公共属性和公共方法。但是可以通过 showhide 来实现只导入部分内容。

show: 执行要导入的内容
hide: 隐藏要导入的内容,导入其他未隐藏的内容。

//只导入sum
import './utils.dart' as Utils show sum;

在这里插入图片描述

//导入除sum以外的其他内容
import './utils.dart' as Utils hide sum;

在这里插入图片描述

导入多个工具类

这个跟node.js 非常类似,就是定义一个公共入库文件,比如 index.dart ,在该文件中导出其他类

export 'utils.dart';

使用时只需要导入 index.dart

猜你喜欢

转载自blog.csdn.net/weixin_41897680/article/details/125753378