【问题标题】:How can I resolve sorbet error: "Use of undeclared variable"?如何解决冰糕错误:“使用未声明的变量”?
【发布时间】:2022-01-27 13:58:02
【问题描述】:

我正在尝试将冰糕类型信息添加到我的 gem pdf 阅读器中。我不希望 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)

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

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

【问题讨论】:

    标签: ruby sorbet


    【解决方案1】:

    根据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 支持。另一方面,另外,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_readers,所以可能就足够了

    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
    

    相信,this也会隐式输入对应的实例变量,不过我没有测试过这个。

    【讨论】:

    • 使用 RBS 是一个有趣的想法,尤其是当它成为事实上的标准时。我还没有探索过,但我会的。
    • RBI 方法在短期内会更容易,因为我已经在使用 RBI。但是,我尝试将您建议的行添加到 RBI 文件中的相关类中,它似乎没有影响。没有语法错误(耶!),但关于未声明的实例变量的错误仍然存​​在。
    • 它应该在initialize 方法中,也许我应该更清楚一点。我无法(阅读:我太懒了)测试真实的东西,但我用一个简单的 4 行类测试它,该类显示相同的错误,并且在将 let 添加到 initialize 后错误消失了.
    • 哦,对了。这样可行!我没有意识到 RBI 文件中的方法可以有一个主体 - 我认为您的建议是将该行添加到类的主体中。干杯 - 这是一个使这个答案成为可能的 PR:github.com/yob/pdf-reader/pull/415
    • 在我注意到“RBI 文件的语法与普通 Ruby 文件的语法相同,除了方法定义之外,不需要需要实施”,而不是我所期望的“没有实施”。
    猜你喜欢
    • 2017-09-11
    • 1970-01-01
    • 2012-05-31
    • 1970-01-01
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    相关资源
    最近更新 更多