最近学习 Dart 语言,分享一下心得 (入门级)

2020-03-21 22:42:57 +08:00
 cmdOptionKana

每隔一段时间,总有一种新(或较新)的语言进入大家的视线,比如 Kotlin, Rust, Go 等,我查了一下它们的 “出生日期”:

由于 Dart 1 实质上已经被放弃,Dart 2 改动很大几乎就是一种新的语言,因此这里只列出 v2.0 的日期。

一个现象:这些新出的热门语言,都是静态类型语言,其原因可能是现代 IDE 发展起来了。 动态语言最大的优势是 “写起来省键盘”,但在类型推导与现代 IDE 的加持之下, 静态语言写起来不再繁琐,反而动态语言由于更难进行静态分析而难以享受 IDE 提供的更多好处。

言归正传,从上面各语言的日期可见,其中 Dart 2 非常新,这使得它有机会尽情吸收其它语言的经验, 反映出现代编程语言的很多新思想。下面开始说说 Dart 语言的特点。

一切皆对象

甚至连数字都是对象,比如下面的例子,数字可直接调用方法:

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

由于一切皆对象,所以任何变量的默认值都是 null,比如:

int n;
String s;
assert(n == null);
assert(s == null);

代码内测试 (inline testing)

直接在代码内写 assert(), 这个函数只在开发环境中有效,而在生产环境中会被忽略,非常适合用来做一些简单但重要的测试。

类型推导

以前的静态类型语言一般要求每次定义变量时,都明确写明类型,这非常繁琐。 而现在自动推导变量类型这个特性几乎成为了各种新语言的标配,不少老牌语言也在新版中加入这个特性。

var s = 'abc';
assert(s.runtimeType.toString() == 'String');

简化访问权限

不通过 public, protected, private 等关键词来表明成员是否对外公开,而是通过首字母来表示。 类似于 Golang, Golang 是用首字母大写表示 public, 但这被很多开发者诟病,确实会带来一些不便。 而 Dart 则是用首字母为下划线来表示 private, 这就比 Golang 那种设定舒服多了,也很符合直觉。

// 这个例子只是为了说明访问权限,并非最佳实践。
class MyClass {
  int _count;
  
  int get count => _count;
  set count(value) => _count = value;
}

是不是有点像 Python? 但与 Python 不同的是,_count 不是看起来像 private, 而是真的 private !

用问号语法来简化 null 相关操作

这也是新语言中比较流行的一种特性,确实非常好用。

int n;

// 此时 n == null, 可以赋值。
n ??= 3;
assert(n == 3);

// 此时 n != null,保留原来的值。
n ??= 5;
assert(n == 3);

print(1 ?? 3); // 结果为 1.
print(null ?? 5); // 结果为 5.
myObject?.someProperty

// 如果没有问号语法,就会麻烦很多:
(myObject != null) ? myObject.someProperty : null

关于 null 有一个故事,他的发明者曾说这是自己犯下的 “十亿美元错误”(billion-dollar mistake)。 但这么多年过去了,新语言明明有机会采用 “无 null” 设计,却还是选择了有 null, 侧面说明这个发明还是好处多过坏处。

处理列表的常用函数(流式处理)

比如 filter(在 Dart 里是 where), map, any, fold 等等,以前常见于动态类型语言,但由于这些函数确实很方便, 现在很多静态语言里也是标配特性了。

  numbers
    .where((n) => n % 2 == 0)
    .forEach((n) => print(n));

自动提供 getter, setter

在下面的例子中,xy 拥有默认的 getter 和 setter,非常方便。

class Point {
  num x, y;
  Point(this.x, this.y);
}

var p = Point(1.2, 3);
p.y = 2.5;
print('${p.x}, ${p.y}'); // "1.2, 2.5"

Kotlin 也有类似的特性。为什么在已经有了那么多编程语言的情况下,还要不断发明新的语言呢, 原因之一就是这些新特性非常优雅:写起来更方便,读起来更清晰。

异步编程

Future main() async {
  var ver = await getVersion();
  print('In main: version is $ver');
}

胖箭头函数

如果你曾经主要使用 JavaScript, 后来转到别的语言,那么你可能会很怀念那个可爱又实用的胖箭头。 在 Dart 里你可以再次愉快过使用它。

class MyClass {
  int value = 0;  
  void increase() => value++; 
}

串联语法 (Cascade)

Dart 自称是专为客户端(约等于前端)而设计的语言,而这个新颖、高效的串联语法很好地体现了什么叫做 客户端语言,这是 Dart 带给我最大的惊喜!

querySelector('#confirm')
  ..text = 'Confirm'
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

总结

以上列举了 Dart 的一部分特性,可以看出它吸收了很多新特性,同时考虑了别的语言的使用习惯, 学起来会有一种“似曾相识”的熟悉感,用起来会有一种“要啥有啥”的爽感。

再结合它的强大生命力:通过 Flutter 在手机端生存,通过编译为高质量的 JavaScript 代码在网页端生存, 通过编译为二进制可执行文件在桌面电脑端生存,同时也已经被 Google 官方确定为 Fuchsia 的主要编程语言之一。 因此,有兴趣的同学不妨学习一下。

5217 次点击
所在节点    Dart
17 条回复
chinvo
2020-03-21 23:13:14 +08:00
最后还是要编译成 js,和 ts 比也没有太大优势
cmdOptionKana
2020-03-21 23:28:17 +08:00
@chinvo 网页端不是 Dart 的主战场(曾经是,但早就完败了,借助 Flutter 还魂)
itning
2020-03-21 23:45:54 +08:00
刚出 1.0 的时候学过,写了个 app,嵌套的无法想象
cmdOptionKana
2020-03-22 00:00:12 +08:00
@itning 是指 Flutter 1.0 吧? Flutter 我还没学不太了解,据说嵌套是特色,但看起来 Flutter 发展得挺快的,不知道现在有什么变化没。
fan123199
2020-03-22 00:41:00 +08:00
说起这些特性,我还是想起了 kotlin 。kotlin 的语法糖还多一些。
fan123199
2020-03-22 00:41:42 +08:00
不过作为 Android 开发,后面还是要继续学 kotlin 。😀
cmdOptionKana
2020-03-22 01:07:34 +08:00
@fan123199 Kotlin 添加语法特性简直疯狂,非常激进,好处是魔法多、表现力强大,缺点是需要更多时间去熟悉。Dart 还是比较克制的,学起来更轻松一些。
laike9m
2020-03-22 02:26:54 +08:00
你列的很多特性在 Dart 1 里就有了。cascade 确实好,我也很喜欢。
WebKit
2020-03-22 03:16:25 +08:00
@chinvo 优势还是有的,比如我这种不会 web 开发的人,做个简单的 app 然后编译一下,全平台都走了。有点类似 rn,不过流畅性上比 rn 强很多
sagaxu
2020-03-22 08:43:18 +08:00
干不了服务端
secondwtq
2020-03-22 10:34:30 +08:00
有几点我觉得楼主有必要提一下(如果有的话):
* 继承(单继承?多继承?能不能继承 int 等类型?)
* 有没有类似 Java/Go Interface 的机制?
* Operator Overloading/Ad-hoc Polymorphism
* 有没有泛型?或者干脆 大 道 至 简?
mrcn
2020-03-22 10:45:07 +08:00
Append 的那个 ,C#也有
mxalbert1996
2020-03-22 11:50:19 +08:00
扩展方法我见过的最强大的还是 Swift
cmdOptionKana
2020-03-22 12:38:14 +08:00
@secondwtq

Dart 是单继承的,然后提供 Mixin 来解决一些原本需要多继承的场景(这好像也是目前比较流行的方案,因为多继承用起来不容易处理好)。

不能继承 int, double, bool, Null 和 String,但可以扩展方法。

Dart 的每一个 class 都会自动成为 interface (即每一个 class 都可以被 implement ),但一般不建议 implement 普通类,官方建议需要 interface 的时候就用 abstract class 。

有 Operator Overloading 。(那个 ad-hoc Polymorphism 我不懂…)

有泛型的,除了 Go 谁还敢玩大道至简(狗头)。
cmdOptionKana
2020-03-22 12:41:02 +08:00
@mrcn
@mxalbert1996 原来扩展方法也不罕见啊,第一次见的时候感觉特别强大,也很实用。

(现在各种主流语言单说语法的话还真的非常共通)
Tecrafter
2020-03-22 13:08:40 +08:00
有预感使用 Dart 的 Flutter 会一统大前端。
w4mxl
2020-04-09 16:35:54 +08:00
@cmdOptionKana #7 很同意~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/654962

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX