【问题标题】:Why Crystal fails to infer type for instance variable?为什么 Crystal 无法推断实例变量的类型?
【发布时间】:2021-08-12 00:58:03
【问题描述】:

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

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

附言

以后有没有改进的计划?似乎是很常见和有用的东西。

【问题讨论】:

  • 好消息!在 Crystal 1.4 中,它将立即编译。我用详细信息更新了我的答案。

标签: crystal-lang


【解决方案1】:

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

主题came up again recently,现在编译器足够聪明,可以检测到大多数简单的情况(感谢Asterite 对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 来说已经过时了。出于历史原因,我将其保留;它的一部分仍然是相关的,但是像原始问题中的简单案例现在是合法的水晶。只有在旧版本中(直到 1.3.2),它才会推导出 4.days1 + 1

@a = 4 会像 4literal 一样工作,但 4.days 是一个表达式,因此不能自动推导。出于同样的原因@a = 1 + 1also requires explicit types,尽管@a = 2 不会。

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

简而言之,原因是为了保持编译步骤简单。自动归纳类型很优雅,但也有缺点:

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

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

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

您可能会问,为什么它适用于课堂外的第一个作业?我假设在这种情况下,上下文更加本地化。因此,反对允许它的论点并不完全适用。例如,如果您更改函数内部的语句,其效果并不像更改类的布局那样全局。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 2017-08-05
    • 1970-01-01
    • 2020-02-18
    • 2019-03-20
    相关资源
    最近更新 更多