How can I resolve sorbet error: "Use of undeclared variable"?

How can I resolve sorbet error: "Use of undeclared variable"?

我正在尝试将冰糕类型信息添加到我的 gem、pdf-reader。我不希望 sorbet 成为 gem 的运行时依赖项,因此所有类型注释都在 rbi/ 目录的外部文件中。我也无法在 类.

中扩展 T::Sig

我想在某些文件中启用 typed: strict,但这样做会表明我正在使用一些没有类型注释的实例变量:

./lib/pdf/reader/rectangle.rb:94: Use of undeclared variable @bottom_left https://srb.help/6002
    94 |        @bottom_left = PDF::Reader::Point.new(
                ^^^^^^^^^^^^

./lib/pdf/reader/rectangle.rb:98: Use of undeclared variable @bottom_right https://srb.help/6002
    98 |        @bottom_right = PDF::Reader::Point.new(
                ^^^^^^^^^^^^^

./lib/pdf/reader/rectangle.rb:102: Use of undeclared variable @top_left https://srb.help/6002
     102 |        @top_left = PDF::Reader::Point.new(
                  ^^^^^^^^^

./lib/pdf/reader/rectangle.rb:106: Use of undeclared variable @top_right https://srb.help/6002
     106 |        @top_right = PDF::Reader::Point.new(

建议的修复方法是使用 T.let():

@top_right = T.let(PDF::Reader::Point.new(0,0), PDF::Reader::Point)

但是我不能那样做,因为它需要对冰糕的运行时依赖。

是否可以在 rbi 文件中记录实例变量的注释?

根据 the documentation“RBI 文件的语法与普通 Ruby 文件相同,只是方法定义不需要实现。”因此,在 RBI 文件中声明实例变量类型的语法与 Ruby 文件中的相同:

sig do
  params(
    x1: Numeric,
    y1: Numeric,
    x2: Numeric,
    y2: Numeric
  ).void
end
def initialize(x1, y1, x2, y2)
  @top_right = T.let(PDF::Reader::Point.new(0,0), PDF::Reader::Point)
  # …
end

另一种方法是使用 RBS 语法而不是 RBI 语法,它本身支持实例变量的类型注释。但是,我在 Sorbet 中发现了关于 RBS 支持的相互矛盾的信息。网上声称 Sorbet 支持 RBS。 OTOH,the Sorbet FAQ 用将来时谈论 RBS 支持。另一方面,other,FAQ 中提到的“未来”是 Ruby 3 的发布,这实际上是过去一年。

在 RBS 中,它看起来像这样:

module PDF
  class Reader
    @top_left: Numeric
    @top_right: Numeric
    @bottom_left: Numeric
    @bottom_right: Numeric

    class Rectangle
      def initialize: (
        x1: Numeric,
        y1: Numeric,
        x2: Numeric,
        y2: Numeric
      ) -> void
    end
  end
end

或者,因为它们也是 attr_reader,所以只做

可能就足够了
module PDF
  class Reader
    attr_reader top_left: Numeric
    attr_reader top_right: Numeric
    attr_reader bottom_left: Numeric
    attr_reader bottom_right: Numeric

    class Rectangle
      def initialize: (
        x1: Numeric,
        y1: Numeric,
        x2: Numeric,
        y2: Numeric
      ) -> void
    end
  end
end

相信,这样也会隐式类型对应的实例变量,不过我没测试过这个