注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

韩国恺的博客

hanguokai.com

 
 
 

日志

 
 

Dart 语言惯用语——Dart中特有的代码味道(上)  

2011-10-26 14:18:49|  分类: Dart |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
英文原文:Idiomatic Dart
更新日期:2012年11月14日

对于来自其它语言,特别
是 Java 和 JavaScript 的开发者,Dart 语言看起来很熟悉。如果足够努力,你可以使 Dart 代码像那些语言一样。如果你非常努力,你甚至可以把 Dart 变为 Fortran,但是这样你将错过 Dart 中独特和有趣的部分。

本文将帮助您写出符合 Dart 习惯的独特代码。因为语言仍在演进中,所以这里的许多惯用语也在变化。语言中的有些地方我们仍不确定用什么最佳实践好。(也许你能帮助我们。)但这里是一些要点,帮你摆脱 Java 或 JavaScript 的思维惯式,符合 Dart 的习惯。

构造函数
本文将从对象生命周期的起始: 使用构造函数开始。每个对象都将在某一个时刻被构造出来,定义构造函数是定义一个类的重要组成部分。这方面 Dart 有些有趣的想法。

自动初始化字段
首先是摆脱一些单调乏味的部分。许多构造函数仅仅是简单地把参数赋值给字段,如:
  1. class Point {
    num x, y;
    Point(num x, num y) {
    this.x = x;
    this.y = y;
    }
    }

这样我们这里不得不输入4次x,仅仅是初始化一个字段。太烂了。我们可以做的更好:
  1. class Point {
    num x, y;
    Point(this.x, this.y);
    }

在参数列表中,如果参数前使用 this. ,那么这个名字的字段将自动使用该参数值做初始化。这个例子也展示了另外一个小特性:如果一个构造函数体完全是空的,那么可以只使用一个分号(;)替代 { }。

命名构造函数
就像大部分动态类型语言一样,Dart 不支持重载。对于方法而言,这没有多少限制,因为你总是可以使用不同的方法名,但是构造函数就没有这么幸运了。为了缓和这种情况,Dart允许你定义命名构造函数:

import 'dart:math';

class Point {
num x, y;
Point(this.x, this.y);
Point.zero() : x = 0, y = 0;
Point.polar(num theta, num radius) {
x = cos(theta) * radius;
y = sin(theta) * radius;
}
}

这里这个 Point 类有三个构造函数,一个标准构造函数和两个命名构造函数。你可以像下面这样使用:
  1. import 'dart:math';

    main() {
    var a = new Point(1, 2);
    var b = new Point.zero();
    var c = new Point.polar(PI, 4.0);
    }

  2. 注意我们这里在调用命名构造函数的时候仍然使用了 new 。它并不是一个静态方法。

工厂构造函数
有一些和工厂(factory)相关的设计模式。当你需要一些类的实例,但是想以更灵活一点的方式,而不是直接
硬编码的方式调用具体类型的构造函数的话,这时这些工厂模式开始发挥作用了。如果你已经有了一个实例也许会想返回之前已经缓存的实例,或者也许你想返回一个不同类型的对象。

Dart 支持这种模式,而且不需要你改变创建对象的方式。你可以定义一个工厂构造函数。当你调用它的时候看起来和普通的构造函数一样。但是构造函数的实现可以做任何想做的事情。例如:
  1. class Symbol {
    final String name;
    static Map<String, Symbol> _cache;

    factory Symbol(String name) {
    if (_cache == null) {
    _cache = {};
    }

    if (_cache.containsKey(name)) {
    return _cache[name];
    } else {
    final symbol = new Symbol._internal(name);
    _cache[name] = symbol;
    return symbol;
    }
    }

    Symbol._internal(this.name);
    }

这里我们有一个表示符号的类。一个符号就像一个字符串,但是我们保证在任意时间点上一个给定的名字只会有一个符号对象。这让你能安全地比较两个对象的相等性仅仅通过测试他们是同一个对象。

这里的默认(未命名)构造函数前加上了 factory 前缀。它告诉 Dart 这是一个工厂构造函数。当它被调用时,它不会创建一个新对象。(工厂构造函数中没有 this 对象)。相反,期望你创建一个实例并明确地返回它。这里我们用给定的名字查找之前缓存的对象,如果找到了就重用它。

最酷的是调用者根本看不出这点。它们只需要:
  1. var a = new Symbol('something');
    var b = new Symbol('something');

第二个 new 将返回之前缓存的对象。这很好,因为这意味着如果我们起初不需要工厂构造函数但之后又认为需要时,我们将不必把所有之前使用 new 的地方都改为静态方法调用。

函数
像大部分现代语言一样,函数是 Dart 中的头等公民(first-class),带有完整的闭包和轻量型语法支持。函数就像任何其它对象一样,你可以毫不犹豫地任意使用它们。特别是,在 Dart 团队中我们大量使用函数用作事件处理器(event handler)。

Dart 有三种创建函数的表示法:一个是命名函数,一个是有函数体的匿名函数和一个表达式函数体的函数。命名形式的函数像这样:
  1. void sayGreeting(String salutation, String name) {
    final greeting = '$salutation $name';
    print(greeting);
    }

这看起来像是一个普通的C语言函数或者Java、JavaScript中的方法。和C、C++不同的是,这些可以嵌入到另一个函数的中间。如果你不需要给出函数的名字,也可以使用匿名形式。和上面代码类似,但没有名字或返回类型,像这样:
  1. window.on.click.add((event) {
    print('You clicked the window.');
    })

这里我们传递一个函数到 add() 方法中,注册了一个事件处理器。最后,如果你需要一个真正的轻量型函数,仅仅对单一表达式求值并返回,使用 => :
  1. var items = [1, 2, 3, 4, 5];
    var odd = items.filter((i) => i % 2 == 1);
    print(odd); // [1, 3, 5]

一个括号的参数列表,跟着一个 => 和一个单一的表达式就创建了一个带参数并返回表达式结果的函数。

实际上,如果可以的话,我们更喜欢使用这种箭头函数,因为它简洁且容易识别,感谢 => 。我们经常使用匿名函数作为事件处理器和回调函数。命名函数反而使用很少。

Dart 还有一个技巧,这是我最喜欢的语言特性之一:可以使用 => 定义成员。你当然可以这样写:
  1. class Rectangle {
    num width, height;

    bool contains(num x, num y) {
    return (x < width) && (y < height);
    }

    num area() {
    return width * height;
    }
    }

但是这样做不是更好吗:
  1. class Rectangle {
    num width, height;
    bool contains(num x, num y) => (x < width) && (y < height);
    num area() => width * height;
    }

我们发现箭头函数非常适用于定义简单的 getter 和其它可以实现计算或访问对象属性的单行方法。

  评论这张
 
阅读(2527)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018