【问题标题】:How would you do rose memoization with Sorbet?你将如何使用 Sorbet 进行玫瑰记忆?
【发布时间】:2019-11-03 17:02:29
【问题描述】:

试图注释此代码,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 声明变量的类型,但还没有具体弄清楚如何。

【问题讨论】:

  • strict 模式不支持在构造函数之外声明的 ivars。将模式更改为true 将使错误消失。

标签: ruby sorbet


【解决方案1】:

从 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

→ View on 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

→ View on sorbet.run

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

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

  1. 使用不同的严格级别

Docs on strictness levels.

如果您觉得添加类型注释太繁琐,您可以使用# typed: true 选择不要求类型注释,其中需要为实例变量添加类型注释的错误会被消除。

【讨论】:

    猜你喜欢
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-20
    • 2022-01-21
    • 1970-01-01
    相关资源
    最近更新 更多