简述:git
这是一篇译文,来自于Dartlang官方在Medium上的一篇文章,文章中说到Dart正在从新设计它的类型系统,而且即将要加入可空类型和非空类型(这一点和Kotlin语言是极其的类似,正由于这种可空和非空的类型系统的严格划分,才能让Kotlin很好地避免NPE的问题)。为何要翻译一篇这样的文章,算为咱们下一篇语法篇Dart类型系统和泛型作一个铺垫。由于当你进入Dart类型系统,你会发现它其实是一个不严格的类型系统,好比泛型型变安全方面。github
翻译说明:算法
原标题: Dart nullability syntax decision: a?[b] or a?.[b]数组
原文地址: medium.com/dartlang/da…安全
原文做者: Kathy Walrathmarkdown
Dart正在从新设计其类型系统,以便于各个类型都存在可空(该类型的表达式能够有null值)或者非空两种类型。今年晚些时候,咱们将告诉您具体的发布时间和流程。可是Dart默认状况下都将不可为null, 而且当你须要为null的时候,必须使用特殊的语法来讲明当前类型容许使用null值。ide
例如,当你要声明一个整型能够为null,则须要在声明的类型后面加一个?
函数
int? someInt; // someInt变量能够为null
复制代码
若是你看过Kotlin、Swift或C#代码,可能对问号?
语法并不陌生。可是也存在一些不一样的地方---特别是常常用来访问集合和数组中的下标([]
)运算符。C#和Swift都是使用?[]
,而目前Dart(以及ECMAScript)的计划是使用?.[]
语法。源码分析
e1?.[e2] //若是e1为null,就返回null; 不然就返回e1[e2]的值
复制代码
这篇文章主要说明作这个定案背后的缘由,并鼓励你能有一些本身的想法和建议。这些内容大部分都是基于Bob Nystrom对issue #376的评论,该评论总结了Bob和NNBD规范负责人LeafPetersen之间的讨论。post
e1?[e2]
与e1?.[e2]
两种方式都有各自的优势。
e1?[e2]
:
!
运算符(即便它是可空类型,也可使用它在表达式后面添加,表示它的值不为null)的语法: e1![e2]
e1.[e2]
:
e1..[e2] //级联语法
e1?..[e2] // 可空检查的级联语法
复制代码
e1?.e2()
{ e1 ? [e2] : e3 }
咱们花了一段时间尝试找到避免?[]
歧义的方法。问题在于你没法判断这这段代码{e1 ? [e2] : e3}
是不是一个包含条件表达式结果的set集合,或者是一个包含可空检查下标key的map集合。
若是咱们经过添加括号方式来消除歧义,能够选择在整个表达式周围添加--{ (e1 ? [e2] : e3) }
--能够明确地把它当作一个set集合。或者咱们能够将括号包裹第一部分的周围--{ (e1?[e2]) : e3) }
--能够明确把它当作一个map集合。可是在没有括号的状况下,解析器就不知道该怎么作了。
对于这种歧义有多种解决方案,可是彷佛没有一个使人满意的解决方案。一种方法是依靠空格来区分选项。在这种方法中,由于这个空格在?
和[
之间,因此你老是会把e1 ? [e2]
做为条件表达式的前半部分。并且你老是将e1?[e2]
做为可空检查的下标,由于这两个标记之间没有空格。可是依赖空格确实对开发者体验很差。
从理论上来讲,在格式化代码中,依靠空格不是问题。可是不少用户将未格式化的Dart代码编写做为格式化程序的输入。所以,在该语言的每一个地方,这样输入格式将变得对空格更加敏感且脆弱。到目前为止,在Dart中这类状况不多见,这是一个不错的语法特性。(好比- - a
和--a
都是有效的但却有着不一样的含义
忽略歧义问题,使用圆点语法还有另外一个缘由: 若是咱们为其余运算符(例如e1?.+(e2)
等)添加可检测空值的形式,则可能须要使用点号。
咱们为NNBD讨论的另外一项功能是可检查null的调用语法。若是咱们在此处不须要点,则它也存在相同的歧义问题:
var wat = { e1?(e2):e3 }; // Map or set?
复制代码
不管咱们为?[
这种形式给出什么解决方案,它都必须一样适用于?(
这种形式。 最后,考虑链式调用下标的示例:
someJson?[recipes]?[2]?[ingredients]?[pepper]
复制代码
在咱们看来,这看起来不太好。它看上去不像是方法链,而更像是中缀运算符的某种组合-有点像??
运算符。将其与如下代码进行比较:
someJson?.[recipes]?.[2]?.[ingredients]?.[pepper]
复制代码
在这里,它显然是一个方法调用链。视觉上看起来也很明显,由于用户须要快速了解有多少表达式会出现空短路。
总结这么多,彷佛看起来咱们应该使用?.[
下面列举一些缘由:
?.
做为单个"空检查"令牌)咱们一直对反馈和建议很重视,对于这种语法给出反馈最好方式就是对语言issue #376发表评论(或者给一些评论点赞)。那么在使用的时候,请能够考虑查看咱们正在使用其余不错的语言特性。
您能够在这里找到更多信息:
NNBD:
Dart语言的其余变动和特性:
其实这篇文章主要就是讨论一下,关于在Dart语言中对于数组或集合下标可空语法的表达是应该用a?[b]
仍是使用a?.[b]
. 而后做者给出一些为何会使用a?.[b]
的缘由。经过这篇文章,咱们应该还获得一个信息就是Dart正在重构它的整个类型系统,它会像Kotlin那样把类型系统分为可空类型和非空类型,从而实现使得整个类型系统更加完备和严谨。
Dart可空和非空类型已经处于实验阶段,可是在Dart2.x源码中已经在开始使用了。
好比dart中的ListQueue
的源码
//
class ListQueue<E> extends ListIterable<E> implements Queue<E> {
static const int _INITIAL_CAPACITY = 8;
List<E?> _table;//声明List<E?>集合,泛型类型参数E为可空类型
int _head;
int _tail;
int _modificationCount = 0;
/// Create an empty queue.
///
/// If [initialCapacity] is given, prepare the queue for at least that many
/// elements.
ListQueue([int? initialCapacity])//声明可空类型的int
: _head = 0,
_tail = 0,
_table = List<E?>(_calculateCapacity(initialCapacity));
static int _calculateCapacity(int? initialCapacity) {
//对可空类型initialCapacity作空检查
if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) {
return _INITIAL_CAPACITY;
} else if (!_isPowerOf2(initialCapacity)) {
return _nextPowerOf2(initialCapacity);
}
assert(_isPowerOf2(initialCapacity));
return initialCapacity;
}
...
}
复制代码
可是须要注意的是目前尚未直接开放给开发者,还处于experiment阶段。
因此,相信很快Dart中的可空和非空类型将会转正正式使用,到那时候学过Kotlin、Swift或C#的开发者将会对Dart类型系统有更深的认识。有了这一篇的铺垫,咱们下一篇就能够正式进入Dart中的类型系统了,下一篇咱们会将Dart中可选类型、泛型、协变、泛型类型具体化等。
这里有最新的Dart、Flutter、Kotlin相关文章以及优秀国外文章翻译,欢迎关注~~~