Nim lang 尼姆:如何证明不是零?
对我来说,Nim最有趣的特性之一是Nim lang 尼姆:如何证明不是零?,nim-lang,Nim Lang,对我来说,Nim最有趣的特性之一是not nil注释,因为它基本上允许在编译器的帮助下静态地完全排除各种NPE/access违规错误。然而,我在实践中很难使用它。让我们考虑一个最基本的用例: 类型 SafeSeq[T]=序列[T]不是零 这里的一个直接陷阱是,即使实例化这样的SafeSeq也不是那么容易。尝试 s:SafeSeq[int]=newSeq[int](100) 出现错误时失败无法证明'newSeq(100)'不是零,这令人惊讶,因为人们可能会认为newSeq根本不是零。解决方案似
not nil
注释,因为它基本上允许在编译器的帮助下静态地完全排除各种NPE/access违规错误。然而,我在实践中很难使用它。让我们考虑一个最基本的用例:
类型
SafeSeq[T]=序列[T]不是零
这里的一个直接陷阱是,即使实例化这样的SafeSeq
也不是那么容易。尝试
s:SafeSeq[int]=newSeq[int](100)
出现错误时失败无法证明'newSeq(100)'不是零
,这令人惊讶,因为人们可能会认为newSeq
根本不是零。解决方案似乎使用以下帮助器:
proc newSafeSeq*[T](大小:int):SafeSeq[T]=
#我想只有@[]表达式可以证明不是零
结果=@[]
结果设置(大小)
下一个问题出现在尝试使用SafeSeq
执行某些操作时。例如,当您映射到一个SafeSeq
时,您可能会期望结果不会再次为零。但是,类似的方法也失败了:
让a:SafeSeq[int]=@[1,2,3]
设b:SafeSeq[string]=a.mapIt(string,$it)
一般的问题似乎是,一旦返回类型变成普通的seq
时,编译器似乎忘记了not nil
属性,无法再证明它
我现在的想法是引入一个小的(可以说是丑陋的)助手方法,它允许我实际证明而不是nil
:
proc proveNotNil*[T](a:seq[T]):SafeSeq[T]=
如果是零:
结果=a#意外,仍然错误“无法证明‘a’不是零”
其他:
引发新异常(ValueError,“无法转换”)
#这应该允许:
设a:SafeSeq[int]=@[1,2,3]
设b:SafeSeq[string]=a.mapIt(string,$it).proveNotNil
但是,编译器在这里也无法证明不是nil
。我的问题是:
- 在这种情况下,我应该如何帮助编译器推断
而不是nil
- 此功能的长期目标是什么,即是否有计划使推断
更强大?手动而不是nil
的问题在于它可能不安全,而且违背了编译器负责证明它的想法。但是,如果只在非常罕见的情况下才需要proveNotNil
,则不会造成太大的伤害proveNotNil
注:我知道
seq
试图成为nil
不可知论者,即,即使在nil
情况下,一切都正常。但是,这仅适用于Nim内部。当与C代码接口时,nil隐藏原则成为错误的危险来源,因为nil
序列仅在Nim端无害…使用isNil魔法检查nil:
type SafeSeq[T] = seq[T] not nil
proc proveNotNil[T](s: seq[T]): SafeSeq[T] =
if s.isNil: # Here is the magic!
assert(false)
else:
result = s
let s = proveNotNil newSeq[int]()
我想标准库需要做一些工作,例如注释
newSeq
返回not nil
seqNice,谢谢,这正是我想要的。我以前从未听说过isNil
,例如,手册中没有提到它。但是,从条件中推断“非零”需要编译器魔法,这是有道理的。在2020年,激活nil跟踪“编译器魔法”不再需要.isNil<如果s==nil足以满足编译器的要求,则为code>。