Dart语法快速上手五 《Dart2之类与构造方法》


使用构造方法

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});

var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});

上面这两种写法都是可以的,Dart2中new关键字已经成为一个可选项

常量构造方法

有些类提供常量构造函数。要使用常量构造函数创建编译时常量,请将const关键字放在构造函数名称之前

var p = const ImmutablePoint(2, 2);

构造两个相同的编译时常量会产生一个规范的实例:

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // They are the same instance!

如果将const关键字前置的话,后面的const是可以省略的,比如

// Lots of const keywords here.
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

上面的代码可以写成

// Only one const, which establishes the constant context.
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

获取运行时类型

要在运行时获取对象的类型,可以使用Object的runtimeType属性,该属性返回Type对象。

print('The type of a is ${a.runtimeType}');

声明构造函数

class Point {
  num x, y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}

上面是一种简化版的构造函数,只是为了赋值,所以省略了方法体

如果您未声明构造函数,则会为您提供默认构造函数。
默认构造函数没有参数,并在超类中调用无参数构造函数。

命名构造函数

使用命名构造函数为类实现多个构造函数或提供额外的清晰度:

class Point {
  num x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}

跟Java等语言不同,Dart的多重构造方法是一种类名.自定义方法名来实现的,如果你按照传统的方法来写的话,例如这样:

class Grammar2 {
  var x, y, z;

  Grammar2(this.x,this.y);  //错误

  Grammar2(this.x); //不能同时拥有两个这样的构造函数

}

正确的写法

class Grammar2 {
  var x, y, z;

  Grammar2.translate(this.x, this.y); //TODO 构造方法的重载

  Grammar2(this.x,this.y);
  

   printRealVar() {
    print('x=' + x.toString() + "y=" + y.toString());
    return 2;
  }

 @override
  String toString() {
    // TODO: implement toString
    return "this is Grammar2";
  }
}

调用非默认的超类构造函数

默认情况下,子类中的构造函数调用超类的未命名的无参数构造函数。
超类的构造函数在构造函数体的开头被调用。
如果还使用初始化列表,则在调用超类之前执行。
总之,执行顺序如下:

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}

这段代码的执行结果就是:
in Person
in Employee

除了调用超类构造函数之外,还可以在构造函数体运行之前初始化实例变量。
用冒号分隔初始化程序。

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

这个示例中,我们在调用fromjson这个构造方法之前我们抢先初始化了x和y的值,中间用冒号隔开

你也可以在调用初始化方法之前进行一些参数的验证,比如:

Point.withAssert(this.x, this.y) : assert(x >= 0) {
  print('In Point.withAssert(): ($x, $y)');
}

这个示例中,构造方法调用之前,我们验证了x必须为正数

构造函数的重定向

我们在开发中经常会有这样的情景,我们构造了好几个构造方法,但是这些构造方法本身并不执行任何操作,只是为了调用其他构造 方法,在Dart中,我们称之为构造方法的重定向(这个语法在前面示例中出现过)

class Point {
  num x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}

常量构造方法

假如你的示例在整个程序从始至终都不会变更实例,这个时候你可以考虑一下使用常量构造方法,在构造方法前面加上const关键字(是不是很像单例模式?)

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}

工厂构造方法

跟工厂设计模式类似,需要什么给你什么,根据一个特定的标识产生不同的实例,在Dart中,通过传入一个特定的标识符,来查看我的静态缓存里面有没有这个缓存,如果有,直接返回,如果没有,我便new 一个对象存入缓存再返回

class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

工厂构造函数无权访问 this

对象之间的操作符运算

您可以覆盖下表中显示的运算符。
例如,如果定义Vector类,则可以定义一个+方法来添加两个向量。(翻译自官网)


image.png

来个示例,自己体会

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  // Operator == and hashCode not shown. For details, see note below.
  // ···
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}

要在代码尝试使用不存在的方法或实例变量时检测或做出反应,您可以覆盖noSuchMethod():

class A {
  // Unless you override noSuchMethod, using a
  // non-existent member results in a NoSuchMethodError.
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}

枚举类

enum Color { red, green, blue }

枚举中的每个值都有一个索引getter,它返回枚举声明中值的从零开始的位置。
例如,第一个值具有索引0,第二个值具有索引1。

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

要获取枚举中所有值的列表,请使用枚举值常量。

List<Color> colors = Color.values;
assert(colors[2] == Color.blue);

switch case中使用枚举

var aColor = Color.blue;

switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // Without this, you see a WARNING.
    print(aColor); // 'Color.blue'
}

Mixin

Mixins是一种在多个类层次结构中重用类代码的方法,B继承于A,但是B也要用到C的一些特性,多继承在很多语言中是行不通的,Dart中的Mixin就是为了解决这种问题出现的

要使用mixin,请使用with关键字,后跟一个或多个mixin名称。
以下示例显示了两个使用mixins的类:

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

注意:要实现一个mixin,创建一个扩展Object的类,声明没有构造函数,并且没有调用super。
例如:

abstract class Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

泛型方法(只看代码不解释,跟java几乎一样)

T first<T>(List<T> ts) {
  // Do some initial work or error checking, then...
  T tmp = ts[0];
  // Do some additional checking or processing...
  return tmp;
}

导入

Dart目前都要手动导入包,Dart内置的library可以直接用import 'Interface.dart';方法导入,自定义的包可以在前面加入一个package关键字导入

import 'package:flutter_app/Grammar2.dart';
import 'SuperGrammar.dart';
import 'Interface.dart';
import 'FactoryClass.dart';
import 'package:meta/meta.dart';
import 'ConstantClass.dart';

有一种情况例外,加入导入的两个包里面有同名的类,这个时候如何区分,java 是用全路径来标识,Dart里面可以给这个包里面所有的类设置一个别名

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;  //这里利用as来设置 别名

// Uses Element from lib1.
Element element1 = Element();

// Uses Element from lib2.
lib2.Element element2 = lib2.Element();

如果你想导入的是一个包中的部分类

// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;

设置这个功能的出发点是可以降低包体积么??? 不得而知

improt 懒加载

这个是为了在使用导入的类的时候才会去载入这个包,主要是为了提升启动效率

如果需要使用懒加载的功能,请使用deferred as 关键字

import 'package:greetings/hello.dart' deferred as hello;

//需要的时候调用别名.loadLibiary方法
Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

在前面的这段代码中 await 关键字的作用是暂停程序的运行直到包导入完成

  • 延迟库的常量不是导入文件中的常量。
    请记住,在加载延迟库之前,这些常量不存在。

  • 您不能在导入文件中使用延迟库中的类型。
    相反,请考虑将接口类型移动到由延迟库和导入文件导入的库。

  • Dart隐式地将loadLibrary()插入到使用deferred as namespace定义的命名空间中。loadLibrary()函数返回Future。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容