问题
Trying to annotate this code, the rose memoization (@||=
) gives me an error 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
As far as I've found, I should declare the variable's type with T.let
but haven't figured out specifically how.
回答1:
Sorbet now has built-in support for this, as of 0.4.4679. Before that, there were other workarounds (see below).
- Initialize the instance variable as
T.nilable
, and replace all direct access of the instance variable elsewhere with the method:
# 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
This is the the preferred solution.
- Initialize the instance variable outside of the method, and give it a type annotation:
# 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
Conceptually, there are two phases of execution for this class: when it's initialized, and when it's used. If an instance variable is not given a type annotation when it is initialized in Sorbet, it will be T.untyped
everywhere (or an error in # typed: strict
). Because if it's not annotated in the initialize, Sorbet can't know which code path might write into this location first. (Even in this case where there is one location, Sorbet doesn't do that sort of global analysis.)
Sorbet only relaxes this when the instance variable is nilable, in which case it can be initialized anywhere, because Sorbet doesn't need to guarantee that it's initialized as non-nil.
- Use a different strictness level.
Docs on strictness levels.
If you find it too burdensome to add a type annotation, you can opt out of requiring a type annotation by using # typed: true
, where the error requiring type annotations for instance variables is silenced.
来源:https://stackoverflow.com/questions/56693361/how-would-you-do-rose-memoization-with-sorbet