Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2013-08-03) Dart实战 (2) Dart语言特点

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

第一眼看起来,Dart的语法有点像Java/C#/JavaScript,据说是为了让人们容易上手。不过Dart有它自己的原则和特点,这导致它和它们在某些方面是有明显的不同,还是得花一些时间思考和研究的。

首先是语法上一些比较熟悉的特性:

  1. 语法整体看起来跟Java很相似
  2. Dart中有class,但没有nested class
  3. 有properties,还可用get/set关键字定义getter/setter
  4. 有static method
  5. 有一等函数,可当作值传递
  6. 参数可声明为函数的形式
  7. 参数可声明为可选参数,和具名参数
  8. 使用大括号
  9. 每行以分号结尾
  10. 有library,用于分模块,跟js里的module比较像。暂无nested library
  11. 可导入另一个library,可起别名,或只导入部分
  12. this指向当前类的实例
  13. 语句分为expr和statement,其中前者有返回值,后者无
  14. 有annotation
  15. 有型泛

一些比较独特的特性:

  1. 没有private/protected/public等关键字,而将所有以下划线_开头的作为private,普通字母开头的作为public
  2. library的双向声明,part与part of
  3. 同时有final和const两个关键字
  4. 不能动态修改类,比如添加删除方法等,但提供了noSuchMethod(),可捕获未声明的调用
  5. 没有eval,不能动态执行代码
  6. 每一个类都有一个隐含的对应接口,所以我们可以直接implement另一个类。

关于类型:

Dart提供了可选的类型系统,在声明变量、定义函数的时候,可以指定类型,也可以不指定,不指定的话就是dynamic。

Dart的类型系统比较独特的地方在于,类型仅仅是给编辑器和编译器看的,它不应也不会对代码的行为产生任何影响。在production模式下,类型会被忽略,以获得更好的性能。我们在执行dart代码时,可以指定-checked参数,打开或关闭运行时的类型检查(默认未开启)。

由于类型系统不对代码行为产生影响,所以没法通过参数类型来区分两个同名方法,没法进行重载。同时也没法实现像C#中的扩展方法,即声明一个static方法:

 public static void fullName(User user) { return user.firstName + user.lastName; } 

然后调用:

 User user = getUserFromSomewhere(); user.fullName(); 

开发团队说正在想其它办法提供类型的功能。

所以我们只能把类型看作是对编辑器的提示,可用来让编辑器帮我们提示方法、变量,以及检查我们调用时是否打错了字。也因此我们可以实现一些在别处做不到的魔术:随便给一个变量指定任意一个类型,让编辑器帮我们提示,同时利用noSuchMethod(),来处理我们对该对象的调用:

 class User { String name; } class Animal { String roaring; } class Ghost { noSuchMethod(Invocation msg) { // handle missing invocations } } User user = new Ghost(); user.name = "Freewind"; Animal animal = new Ghost(); animal.roaring = "hahaha"; 

虚拟机、线程、isolate

Dart运行在自己的虚拟机DartVM上,它跟nodejs所在的v8有点像。虽然有了虚拟机,但并不像java/c#那样,下面还有一些字节码,Dart本身就相当于字节码。关于这个选择,开发团队在一个文章中说了很多原因,不过最后总结为一句:对于Dart来说,使用字节码没有更多好处,使用Dart语言本身也没有更多坏处,所以就没搞字节码了。

关于线程,Dart代码运行于单线程环境中,这跟nodejs很像。这意味着我们不需要担心多线程的那些锁啊同步什么的问题,就算对一个全局变量进行读写,也不用考虑会不会被其它线程改了(当然还是建议少使用全局变量)。dart内置库中提供了Future,很多IO或耗时的操作,都返回的是Future对象,然后在它的then()方法中传个回调进去,这跟nodejs也是很像的。好在Dart直接内置了这种标准做法,不像js那里,有无数的库想来解决这个问题。

由于单线程无法很好的利用多核,所以Dart提供了一个 isolate库。我们在可以在自己的代码中,使用spawnFunction(…)函数,新起一个isolate出来,执行指定的函数。一个isolate跟一个线程有点像,比如普通的Dart代码也是运行在一个isolate中。但不同的是,两个isolate之间是不共享内存的,所以同一个全局变量,在不同的isolate中是互相独立的,改了这边不会影响那样。这样看起来,每个isolate像是一个进程。两个isolate之间可以互相发消息进行通信,风格有点像actor,消息会clone后发出去。除了通过spawnFunction()指定函数启动外,还可以spawnUrl指定另一个dart文件来启动,然后也之通信。如果是前者,可以传各种对象当消息,如果是后者,只能传一些基本类型,比如string,int之类,作用就有限了。

动态修改

Dart是一门很保守的语言。虽然看它的介绍“要替代JavaScript”时,以为它会是一个比较动态的语言,实际上相当静态。比如:

不支持eval(),不能动态执行一段Dart代码。官方说这是基于性能的考虑,js里不是也不建议使用eval吗?

不能动态添加方法。不过提供了noSuchMethod作为解决方案,可以做到相似的效果

不能导入修改后的代码、不能动态扩展代码。这点比较郁闷,因为就算在java中,我们也可以通过classloader来读取新代码,加入到当前的运行时中,提供新功能。而在Dart中,目前仅有一个spawnUrl能以一种非常有限、基本没用的方式来模拟。这导致我们没法在不重启的情况下,执行新生成的代码(如模板引擎)。

编辑器支持

官方在发布Dart的同时,也提供了一个基于eclipse的Dart Editor,功能还比较丰富,高亮、格式化、代码检查、重构、单步调试等都有了。只是不能跟eclipse结合起来,因为不是插件形式。这让人感觉不太方便,因为很多有用的eclipse插件都用不了了。

Idea也提供了一个Dart的插件,基本功能也有,但有些功能有问题,比如调试用不了,代码检查经常不正常。终于Idea有Dart上落后于eclipse了。

另外,sublime也提供了Dart的高亮文件,但其它功能都比较弱。

我现在基本上就是同时开着IDEA和Eclipse,基本操作在Idea中完成,遇到问题时,切换到Eclipse看看它的错误提示,不能不说,这还是非常有用的。

Dart的开发团队还是相当活跃的,我相信Dart现在那些比较弱的地方,很快就会有改进的。现在非常希望它增加类型于“扩展方法”和“动态导入”这两个功能,不然感觉很多想法都实现不了。

(看到上面的代码又乱了吗!最痛恨wordpress的就是这个了,白排了半天版。所以要尽快把我的dartblog弄好转过去。)

comments powered by Disqus