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

韩国恺的博客

hanguokai.com

 
 
 

日志

 
 

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

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

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

字段,getter 和 setter
说到属性,Dart 使用标准的 object.someProperty 语法使用它们。 当属性是类中的一个真正的字段时,大部分语言就是这样做的。但是 Dart 还允许你定义一些方法,它们看起来像是访问属性,但实际上可以执行任意你想要的代码。在其它语言中,这些被称为 getter 和 setter。这里有个例子:
  1. class Rectangle {
    num left, top, width, height;

    num get right => left + width;
    set right(num value) => left = value - width;
    num get bottom => top + height;
    set bottom(num value) => top = value - height;

    Rectangle(this.left, this.top, this.width, this.height);
    }

这里我们定义了一个 Rectangle 类,它有四个真正的字段:left, top, width 和 height。它还有两对 getter 和 setter 方法定义了两个额外的逻辑属性:right 和 bottom。在你使用这个类时,真正字段与 getter 和 setter 没有可见的区别:
  1. var rect = new Rectangle(3, 4, 20, 15);
    print(rect.left);
    print(rect.bottom);
    rect.top = 6;
    rect.right = 12;

字段和 getter/setter 间的模糊处理是语言的基本原则。看待它的最清楚的方式就是认为字段仅仅是用魔法实现的 getter 和 setter。这意味着你可以做些有趣的事情,比如用字段覆盖继承的 getter 方法,或反之。如果接口定义了一个 getter,你可以简单地用一个同名、同类型的字段实现接口。如果字段是可变的(非 final),那么它也可以实现接口要求的 setter。

实际上,这意味着你不必像在 Java 或 C# 中那样防御性地把字段隐藏到 getter 和 setter 样板方法里来隔离它们。如果你有需要暴露的属性,只需让它成为一个 public 的字段。如果你不想它们被修改,只需加上 final。

稍后,如果你需要做一些验证或什么其它事情,你随时可以用 getter 和 setter 代替这个字段。比如我们想确保 Rectangle 类总是有非负的大小,我们可以把它改成这样:
  1. class Rectangle {
    num left, top;
    num _width, _height;

    num get width => _width;
    set width(num value) {
    if (value < 0) throw 'Width cannot be negative.';
    _width = value;
    }

    num get height => _height;
    set height(num value) {
    if (value < 0) throw 'Height cannot be negative.';
    _height = value;
    }

    num get right => left + width;
    set right(num value) => left = value - width;
    num get bottom => top + height;
    set bottom(num value) => top = value - height;

    Rectangle(this.left, this.top, this._width, this._height);
    }

现在我们修改了这个类增加了一些验证,但是根本不影响那些已经使用了它的代码。

顶层定义
Dart 是“纯”面向对象的语言,变量中的任何东西都是一个真正的对象(没有特殊的原始类型),并且每个对象都是某个类的实例。然而它不是教条式的 OOP 语言。它不要求你把所有东西都定义在类里。相反,如果你愿意,你可以在顶层自由地定义函数、变量甚至是 getter 和 setter。
  1. import 'dart:math';

    num abs(num value) => value < 0 ? -value : value;

    final TWO_PI = PI * 2.0;

    int get today {
    final date = new Date.now();
    return date.day;
    }

即使是那些不要求你把所有东西都放在类或对象中的语言,如 JavaScript,它们一般仍然是用一种命名空间的形式:相同名字的顶层定义会导致不经意的冲突。为解决这个问题,Dart 使用一种库系统,允许你用一个前缀导入其它库中的定义来消除歧义。这意味着你不需要防御式地把定义放到类中。

我们仍在探索这实际意味着我们应如何定义库。例如,我们过去习惯于定义一个 Math 类,但现在我们把所有的功能都从 Math 类中移到了 dart:math  库的顶层方法。

我们确实有一些使用顶层定义的例子。首先你需要运行的 main() 函数就是在顶层定义的。如果你使用 DOM,你熟悉的 document 和 window “变量”实际上就是 Dart 中在顶层定义的 getter。

字符串和插值
Dart 有几种字符串字面值。你可以用单引号或双引号,也可以用三引号的多行字符串:
  1. 'I am a "string"'
    "I'm one too"

    '''I'm
    on multiple lines
    '''

    """
    As
    am
    I
    """

字符串没有 + 操作符。使用字符串插值更清晰、更快:
  1. var name = 'Fred';
    var salutation = 'Hi';
    var greeting = '$salutation, $name';

在字符串中,一个美元符号($)跟着一个变量将被扩展为该变量的值。(如果变量不是字符串将调用它的 toString() 方法)。你也可以在大括号里插入表达式:
  1. import 'dart:math';
    main() {
    var r = 2;
    print('The area of a circle with radius $r is ${PI * r * r}');
    }


操作符
Dart 使用你熟悉的 C、Java 语言里一样的操作符和优先级。它们会按你期望的方式工作。而在背后,它们有点特殊。在 Dart 中,使用操作符的表达式如 1 + 2,实际上仅是调用方法的语法糖。对语言而言,这个例子看起来更像是 1.+(2) 。

这意味着你也可以为你自己的类型重载(大多数)操作符。例如,这是一个 Vector 类:
  1. class Vector {
    num x, y;
    Vector(this.x, this.y);
    operator +(Vector other) => new Vector(x + other.x, y + other.y);
    }

这样,我们可以使用熟悉的语法形式做向量加法:
  1. var position = new Vector(3, 4);
    var velocity = new Vector(1, 2);
    var newPosition = position + velocity;

话虽如此,但请不要过度滥用。我们给你汽车的钥匙,并且相信你不会掉头把车开到客厅里。

在实践上,如果你定义的类型在“现实世界”中(在黑板上?)经常使用操作符,那么它可能是一个好的操作符重载的候选者,如:复数、向量、矩阵等。另外,也不一定,自定义操作符的类型一般也应该是不可变类型。

注意因为操作符调用实际上仅仅是方法调用,它们具有固有的不对称性。方法总是在左边的参数上查找。所以当你做 a + b 的时候,是根据 a 的类型决定其意义的。

相等性
有一类操作需要特别注意。Dart 中有两种相等比较:== 和 != ,以及 identical() 函数

== 和 != 做相等测试。它们应该是你99%的时候使用的。和JavaScript不同,它们不做任何隐式转换,所以它们应该如你所期待的那样工作。别害怕使用它们。和 Java 不同,它们适用于任何具有等价关系定义的类型比较。不再需要 someString.equals("something") 这样了。

你可以为你自己的类型重载 == 操作符,只要它们有意义。你不必重载 != ,Dart 自动根据你的 == 定义做推断。

使用内建的 identical() 函数来测试引用。 identical(a, b) 仅当 a 和 b 是内存中完全相同的对象时才返回 true 。默认情况下,如果类型没有定义有意义的相等操作符,那么 == 调用将退回到 identical() 。所以你唯一需要用这个的时候是你明确地想要绕过任何用户定义的 == 操作符。

数字
Dart 中有一个 num 类,它有两个子类:int 和 double 。整数是任意大小的,double 是 IEEE 754 标准定义的 64 位浮点数。

在典型的 Dart 代码中, 我们发现我们需要两种类型的数字:
  1. 纯整数,非浮点数。例如,列表的索引。
  2. 任意数字,包括浮点数。
使用 int 处理第一种情况,使用 num 处理第二种情况。必需是浮点数而不能是整数的情况非常罕见,这是 double 所表达的情况。

通常 Dart 中的数字使用 int 或 num ,很少用 double。
  评论这张
 
阅读(1346)| 评论(0)
推荐 转载

历史上的今天

评论

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

页脚

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