0

我有看起来像这样的代码(游乐场链接):

# typed: strict
class A
  extend T::Sig

  sig { returns(T::Array[Integer]) }
  def compute_expensive
    [1, 2, 3]
  end
  
  sig { returns(T::Array[Integer]) }
  def expensive
    @expensive ||= T.let(compute_expensive, T::Array[Integer])
  end
end

这无法进行类型检查,说:

editor.rb:12: The instance variable @expensive must be declared inside initialize or declared nilable https://srb.help/5005
    12 |    @expensive ||= T.let(compute_expensive, Integer)
            ^^^^^^^^^^

我已经尝试了一些方法来解决这个问题……</p>

  • 当我将类型声明为T.nilable(Integer)时,Sorbet 说返回类型与 sig 不匹配。公平的。
  • 当我将类型声明initialize为时@expensive = nil,Sorbet 说不使用下面的定义nil进行类型检查。Integer也很公平。
  • 如果我在 中声明@expensive = []initialize我的分配将||=变得无法访问。
  • 我当然可以说@expensive = compute_expensive if @expensive.empty?然后返回@expensive,但我更感兴趣的是 Sorbet 的类型系统如何适应这种||=模式。

对我来说,这感觉像是 Ruby 中非常常见的模式!我怎样才能让 Sorbet 为我进行类型检查?

4

1 回答 1

2

一个游乐场链接直接返回给您。

所以,真正使用初始化是这里的重要部分。

  sig { void }
  def initialize
    @expensive = T.let(nil, T.nilable(T::Array[Integer]))
  end

因为在实际调用之前 memoization 仍然是 nil,所以你必须允许它是 nil 以及T::Array[Integer],然后你需要将它添加到初始化中以使类听起来。

于 2020-10-07T13:17:00.067 回答