4

尝试注释此代码时,rose memoization ( @||=) 给了我一个错误Use of undeclared variable @git_sha

# typed: strict
# frozen_string_literal: true

module Util
  extend T::Sig

  sig { returns(String) }
  def self.git_sha
    @git_sha ||= ENV.fetch(
      'GIT_REV',
      `git rev-parse --verify HEAD 2>&1`
    ).chomp
  end
end

据我发现,我应该声明变量的类型,T.let但还没有具体弄清楚如何。

4

1 回答 1

9

从 0.4.4679 开始,Sorbet 现在已经内置了对此的支持。在此之前,还有其他解决方法(见下文)。

  1. 将实例变量初始化为T.nilable,并将在别处对实例变量的所有直接访问替换为方法:
# typed: strict
# frozen_string_literal: true

module Util
  extend T::Sig

  sig { returns(String) }
  def self.git_sha
    @git_sha = T.let(@git_sha, T.nilable(String))
    @git_sha ||= ENV.fetch(
      'GIT_REV',
      `git rev-parse --verify HEAD 2>&1`
    ).chomp
  end
end

→ 在 sorbet.run 上查看

这是首选的解决方案。

  1. 在方法之外初始化实例变量,并给它一个类型注释:
# typed: strict
# frozen_string_literal: true

module Util
  extend T::Sig

  @git_sha = T.let(nil, T.nilable(String))

  sig { returns(String) }
  def self.git_sha
    @git_sha ||= ENV.fetch(
      'GIT_REV',
      `git rev-parse --verify HEAD 2>&1`
    ).chomp
  end
end

→ 在 sorbet.run 上查看

从概念上讲,这个类有两个执行阶段:初始化时和使用时。如果一个实例变量在 Sorbet 中初始化时没有给出类型注释,它将T.untyped无处不在(或在 中出现错误# typed: strict)。因为如果在初始化时没有注解,Sorbet 就无法知道哪个代码路径可能先写入这个位置。(即使在这种只有一个位置的情况下,Sorbet 也不会进行那种全局分析。)

Sorbet 仅在实例变量为 nil 时才放宽这一点,在这种情况下,它可以在任何地方初始化,因为 Sorbet 不需要保证它被初始化为非 nil。

  1. 使用不同的严格级别

关于严格程度的文档

如果您发现添加类型注释太繁琐,您可以通过 using 选择不要求类型注释# typed: true,其中需要实例变量的类型注释的错误被静音。

于 2019-06-20T22:10:46.813 回答