Learn Dart Based on Java

在Java的基础上快速学习Dart语言,快速进入Flutter项目开发。

  • 例1:操作符

~/ 整除
b ??= value // b为null,才进行赋值操作
person?.age = 33 // If p is non-null, set its age value to 33
print(person?.age) // person不为null时返回age值,否则返回null

String playerName(String name) => name ?? 'Guest'; 
等价于:
String playerName(String name) => name != null ? name : 'Guest';

instanceof 替换为 is;
as 类型转换(t as Person).name
  • 例2:数据类型

num get area => pi * pow(radius, 2); // num可以用double,dart推荐使用num
int lineCount; // lineCount默认赋值null,dart中一切都是objects;
int 是一个对象类型;
int、double属于num,dart推荐使用num;

  • 例3:工厂模式的两种方法

第一种:新建一个工厂类
Shape shapeFactory(String type) {
  if (type == 'circle') return Circle(2);
  if (type == 'square') return Square(2);
  throw 'Can\'t create $type.';
}
第二种:使用dart中关键字factory,在基类中构造函数中进行处理。
abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle(2);
    if (type == 'square') return Square(2);
    throw 'Can\'t create $type.';
  }
  num get area; // 抽象方法
}

Dart 中 Factory 构造函数作用:不用总是创建新的对象,可以返回已缓存的对象,也可以返回一个子类对象。【工厂模式】

class Logger {
  final String name;
  bool mute = false;
  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);
  }
}
  • 例4:Object等价于dynamic

var name = 'Bob'; // dart推荐
dynamic name = 'Bob';
String name = 'Bob';
  • 例5:final与const的区别

final 要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而 const 要求在声明时初始化,并且赋值必需为编译时常量。final 是惰性初始化,即在运行时第一次使用前才初始化。而 const 是在编译时就确定值了。

定义形式:
var a = 1;
const a = 1;
final a = 1;
int a = 1;
const int a = 1;
final int a = 1;
const aa = [1,2]; 等价于 const aa = const [1,2];

错误区别:
var aa = const [1, 2, 3];
final bb = [1, 2, 3];
aa = const [11, 22, 33];
//bb = const [11, 22, 33]; // 错误,bb不能修改
//aa[1] = 77; // 错误,aa中的内容不能修改
bb[1] = 77;
  • 例6:类型转换

var one = int.parse('1'); // 可见int是个对象
var onePointOne = double.parse('1.1'); // 可见double是个对象
String oneAsString = 1.toString(); // int -> String
  • 例7:函数

bool isNoble(a) { // bool可以省略;a可以不用指定类型
  return a != null; // 所有函数默认返回null
}
  • 可选参数 { } [ ]
    { }调用时需要加上别名
    [ ]调用时是按照顺序
  • 默认参数
    void func({bool bold = false, bool hidden = false}) {...}
  • 函数可以作为参数进行传递

String scream(String str) => "num is "+str;
main() {
  final values = [1, 2, 3, 5, 10, 50];
  for (var length in values) {
    print(scream(length));
  }
}
for循环代替为:
  values.map(scream).forEach(print);
  values.skip(1).take(3).map(scream).forEach(print); // skip从0开始
void printElement(int element) {
  print(element);
}
var list = [1, 2, 3];
list.forEach(printElement);
  • 匿名函数

var list = ['apples', 'bananas', 'oranges'];
list.forEach(**(item)** { // 构建匿名函数
  print('\${list.indexOf(item)}: \$item');
});

var loudify = (msg) => '!!!\ ${msg.toUpperCase()} !!!'; // 构建匿名函数
print(loudify('hello'));
  • 函数嵌套

makeAdder(num addBy) {
  return (num i) => addBy + i; // 返回一个匿名函数
}

void main() {
  var add4 = makeAdder(4);
  print(makeAdder(2)(3) == 5);
  print(add4(3) == 7);
}
  • 例8:类

dart支持抽象类;并且可以在一个文件中定义多个类。

class Bicycle {
  int cadence;
  int _speed; // 下划线表示私有
  int get speed => _speed; // get方法
  int gear;
Bicycle(this.cadence, this.speed, this.gear); // 简化构造函数,不要忘记尾部分号
// 单引号,双引号一样;'''  '''输出多行;var s = r'C://a/b/'(r表示raw)
// ${expression} 表达式
// $variableName 标识符
// => 一行函数或方法
@override
String toString() => 'Bicycle: $speed mph';

// 不能写return   getGear() => return gear;
getGear() => gear;
}
void main() {
// 可以省略new
  var bike = new Bicycle(2, 0, 1);
  print(bike); // Instance of 'Bicycle'
}
  • constant constructors

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1); // a b are the same instance
var c = ImmutablePoint(1, 1); // a c are not the same instance

const构造函数得到的类不能够再改变。

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);
  final num x, y;
  const ImmutablePoint(this.x, this.y);
}
  • Named constructor

class Point {
  num x, y;
  Point(this.x, this.y); // 构造函数:Dart has syntactic sugar to make it easy

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}
  • Named constructor 手动调用父类有参构造函数

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');
  }
} // Warning: The right-hand side of an initializer does not have access to this.

main() {
  var emp = new Employee.fromJson({});
  if (emp is Person) {
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}

Warning: The right-hand side of an initializer does not have access to this.

  • Named constructor 使用已有构造函数

class Point {
  num x, y;
  Point(this.x, this.y);
  Point.alongXAxis(num x) : this(x, 0); // // 不能访问this属性,但可以调用已有构造函数
}
  • get set方法的简化

class Rectangle {
  num left, top, width, height;
  Rectangle(this.left, this.top, this.width, this.height);
  // Define two calculated properties: right and bottom.
  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12; // 调用set right方法
  assert(rect.left == -8);
}
  • implements

Dart中有抽象类,关键字:abstract。
dart没有interface关键字,因为所有的类都定义成了interface,类都是隐式接口。
隐式的接口:每一个类都隐式的定义一个接口,这个接口包含了这个类的所有实例成员和它实现的所有接口。如果相应创建一个类A, 这个类A 支持类B 提供的API函数,但是不继承B 的实现,则类A 需要实现类B 的接口。

class Imposter implements Person, PersonB {
// Person是一个类,实现Person类的所有属性成员和方法。
// 可以“多实现”
}
  • 例9:重载操作符

Dart可以重载操作符【!=不可以进行重载;若重载了==,必须同时重载hashCode】

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);
}
  • 例10:枚举

每个枚举类型都用于一个index的getter,用来标记元素的元素位置。第一个枚举元素的标是0 。

enum Color { red, green, blue }
assert(Color.red.index == 0);
assert(Color.blue.index == 2);
values获取所有枚举值:
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
  • 例11:mixins混合类型使用关键字with

Mixins不是一种在经典意义上获得多重继承的方法。Mixins是一种抽象和重用一系列操作和状态的方法。它类似于扩展类所获得的重用,但它与单继承兼容,因为它是线性的。

class T = A with S; // A中的方法为A和S方法的集合,如果有重复,取S中的。
class T = B with A, S 等价于 class T = (B with A) with S;

注:使用Mixin时必须继承至Object,并且不能调用super()方法。
mixins比较陌生,也比较重要。详细资料参考:
https://juejin.im/post/5bb204d3e51d450e4f38e2f6

  • 例12:泛型

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}
var names = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
  'index.html': 'Homepage',
};

print(names is List<String>); // true
由于Java在运行时会删除掉泛型,所以在Java中只能判读names是否为List,而不能判断是否为List<String>。
var views = Map<int, View>(); // int也是对象
class Foo<T extends SomeBaseClass> { }
泛型方法:T first<T>(List<T> ts) {

  • 例13:Cascade ..

Cascade notation (..) Dart 支持使用两个点号(..)进行级联调用(cascade operator),级联调用和普通方法调用一样,但是它并不返回方法的返回值,而是返回调用对象自身,这样你就可以连续调用同一个对象上的多个方法了。

Cascade ..例子:
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
等价于:
querySelector('#confirm') // Get an object 没有分号
  ..text = 'Confirm'
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
  • 例14:异常Exception和Error

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
  **rethrow;**
} catch (e, s) {
  // No specified type, handles all
  print('Something really unknown: $e');
}
  • 例15:import

import 'package:lib2/lib2.dart' **as** lib2;
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
// To lazily load a library 延迟加载
import 'package:greetings/hello.dart' **deferred as** hello;
  • 例16:异步

Future greet() async { // 必须返回Future,必须有async,await
  await hello.loadLibrary();
  hello.printGreeting();
}

Future<String> lookUpVersion() async => '1.0.0'; // dart会自动添加await

返回Future时,dart会自定添加为:Future<void>;
处理流数据使用await for.

  • 例17:生成器 yield

  • 同步生成器:使用sync*和yield
Iterable<int> naturalsTo(int n) sync* {
  int k = 0;
  while (k < n) yield k++;
}
  • 异步成器:使用async*和yield
Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}
  • 递归生成器 使用yield*
Iterable<int> naturalsDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* naturalsDownFrom(n - 1);
  }
}
  • 例18:Typedefs定义函数

dart中函数也是对象,使用Typedefs定义函数类型。

typedef Compare = int Function(Object a, Object b);
class SortedCollection {
  Compare compare;
  SortedCollection(this.compare);
}
// Initial, broken implementation.
int sort(Object a, Object b) => 0;
void main() {
  SortedCollection coll = SortedCollection(sort);
  assert(coll.compare is Function); // OK
  assert(coll.compare is Compare); // OK
}
  • 例19:元数据@

library todo;
class Todo {
  final String who;
  final String what;
  const Todo(this.who, this.what);
}
使用:
@Todo('seth', 'make this do something')
void doSomething() {
  print('do something');
}
  • 例20:其它

Map中的key和value支持任何数据类型:

Maps:Both keys and values can be any type of object
var gifts = {
  'first': 'partridge',
  10: 'neon', // key可以为num类型
};

main()入口的两种表达方式:

void main() { }
void main(List<String> arguments) { } // 命令行执行携带参数

运行时类型获取 runtimeType:

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

assert的一个使用场景:

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

该文章只是参考Dart官网文档,在Java的基础上,简单的介绍了一下Dart基本语法。以后会对Dart Library进行一些实用性的介绍。

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

推荐阅读更多精彩内容