为什么 Crystal 无法推断实例变量的类型?

Why Crystal fails to infer type for instance variable?

为什么这段代码对实例变量失败?

a = 4.days # Works
class A
  @a = 4.days # Fails
end

P.S.

以后有改进的计划吗?好像是很普通也很有用的东西。

从 Crystal 1.4 开始,现在支持此功能。是合法的代码。

主题 came up again recently, and now the compiler is smart enough to detect most of the simple cases (thanks to Asterite's changes in PR #11812!)。 现在支持以下以前不合法的示例:

class A
  @x = 4.days
end

class B
  @x = 2 * 3 + 4
end

class C
  @x = [1, 2, 3].reverse  # (will be Array(Int32))
end

2022 年 4 月 6 日更新:幸运的是,对于 Crystal 1.4,我之前的回答现在大部分已经过时了。由于历史原因,我将其保留;它的部分内容仍然相关,但像原始问题中的简单案例现在是合法的 Crystal。只有在旧版本中(直到 1.3.2),它才会无法推断 4.days1 + 1.

@a = 4 会工作,因为 4literal, but 4.days is an expression and thus cannot be automatically deduced. For the same reason @a = 1 + 1 ,即使 @a = 2 不会。

关于未来的计划,有趣的是该功能存在,但被有意删除。

总之,就是为了让编译步骤简单。自动归纳类型很优雅,但也有缺点:

  • 编译速度较慢
  • 为错误类型的程序生成良好的错误消息变得困难
  • 重用以前的编译结果变得困难(或不可能?)

原因是,通常,您必须分析贯穿整个源代码的函数调用链。请注意,并非所有表达式都像 1 + 1 这样简单。即使 4.days 已经有些复杂,因为编译器需要推断 days 方法调用的 return 类型。

如果您想了解有关设计决策的更多信息,我建议您阅读 discussion from 2015

您可能会问,为什么它对 class 之外的第一个作业有效?我假设在那种情况下,上下文更本地化。因此,反对允许它的论点并不完全适用。例如,如果您更改函数内的语句,其效果不如更改 class.

的布局那样全局。

同样,这是一个权衡。但是在这两种情况下强制使用类型都会极大地改变体验。虽然在 class 的上下文中效果相当小,但对任何赋值强制显式类型会将“Ruby-like”Crystal 语言变成传统的类型化语言,其中每个赋值需要明确输入。