我已经玩了一段时间的nim,而且经常让我感到困惑的是模板。我希望他们 - 至少在签名级别 - 像procs一样工作,但是他们会错过某些功能(比如可选/默认参数 - 昨天它真的把我扔了一个曲线球)
无论如何,我认为使用模板的模式很简单,所以这里有一些代码:
result
# Name PID Type HomeBrand HomeModel AutoBrand AutoModel
#1 11C AD15E Home A A152 B K235
#2 12C AA05D Home C W54 H H2
#3 20D Z48J Home I A57 D Y0878
编译正确,工作正常。由于我的模板很脏,因此template Kitten*(name: string, age, body: untyped) {.dirty.} =
var kitty_name = name # my {.dirty.} exposes this
echo("Hi, " & name)
if age != 0: echo("wow, " & $age & " years old already!")
body
echo("Bye, " & name)
template Kitten*(name: string, body: untyped) {.dirty.} =
Kitten(name, 0, body)
Kitten("Jimmy"):
echo("It's really nice to meet you, " & kitty_name)
## Ralph and Jimmy cannot co-exist - it's fine, I understand the issue here
# Kitten("Ralph", 5):
# echo("Great that you joined us, " & kitty_name)
内可以使用kitty_name
。取消评论拉尔夫并评论吉米,这也正常。
然后,我意识到body
没有关联的类型。我当然不想要那个 - 我多么愚蠢!所以我解决了这个问题:
age
突然间,吉米没有编译。 Ralph很好--Ralph直接使用模板,但是因为Jimmy使用被覆盖的(如果该术语甚至适用于模板?)方法,突然它就像主要的Kitten关闭了它的边界一样?它不够脏吗?
所以问题是,它为什么有效,它为什么失败,是一个错误或误解的功能?或者我只是滥用模板?
(p.s。在0.17.0和最新的devel分支上试过这个)
答案 0 :(得分:2)
因此,事实证明它不是一个错误。
将其添加到问题跟踪器,并收到Andreas本人的以下回复:
模板的过载需要就无类型参数的位置达成一致。这在手册中有记录。
(我发现的最近的手动条目是nim manual's "Lazy type resolution for untyped" section,我读的越多,我认为它就越少!)
仍然试图绕过这个;我已经尝试了一些简单的例子,我不认为这是整个解释 - 除非结论是"因此混合无类型和类型会导致未定义的行为 - 包括丢弃肮脏的pragma"这并不能让我满怀信心。
有一天,我会深入研究这个代码并更好地解释它。目前,这是一个悬而未决的问题。
答案 1 :(得分:2)
我认为这是一个可以解决的编译器错误,但我会提供当前行为的解释。
这里的关键是在Kitten
的调用站点,涉及注入的kitty_name
变量的块不能被类型检查(由于对不存在的变量的引用)。它们必须作为原始AST传递,这通过使用模板的untyped
参数来指示。一旦引入另一个在同一位置不使用untyped
参数的重载,编译器将尝试在重载解析期间键入检查传入的块,并且您将在调用站点处收到错误(不是在模板扩展后,因为你似乎在假设)。
编译器可能已经使用了几个额外的标准来避免错误 - 例如,它可以根据参数的数量排除其中一个重载。这就是我认为这个问题将来可以解决的原因。
要解决此问题,您可以重命名这两个模板,这样它们就不会重载:
template AgedKitten*(name: string, age: int, body: untyped) {.dirty.} =
block:
var kitty_name = name # my {.dirty.} exposes this
echo("Hi, " & name)
if age != 0: echo("wow, " & $age & " years old already!")
body
echo("Bye, " & name)
template Kitten*(name: string, body: untyped) {.dirty.} =
AgedKitten(name, 0, body)
Kitten("Jimmy"):
echo("It's really nice to meet you, " & kitty_name)
AgedKitten("Ralph", 5):
echo("Great that you joined us, " & kitty_name)
过去,我还对typed和unyped参数之间的区别提供了更深入的解释,您也可以找到它们: