下面是示例代码:
# typed: true
class KeyGetter
sig {params(env_var_name: String).returns(KeyGetter)}
def self.from_env_var(env_var_name)
return Null.new if env_var_name.nil?
return new(env_var_name)
end
def initialize(env_var_name)
@env_var_name = env_var_name
end
def to_key
"key from #{@env_var_name}"
end
def to_s
"str from #{@env_var_name}"
end
class Null
def to_key; end
def to_s; end
end
end
在其上运行srb tc
失败,并
key_getter.rb:7: Returning value that does not conform to method result type https://srb.help/7005
7 | return Null.new if env_var_name.nil?
^^^^^^^^^^^^^^^
Expected KeyGetter
key_getter.rb:6: Method from_env_var has return type KeyGetter
6 | def self.from_env_var(env_var_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Got KeyGetter::Null originating from:
key_getter.rb:7:
7 | return Null.new if env_var_name.nil?
^^^^^^^^
我看到几种解决方法:
.returns(T.any(KeyGetter, KeyGetter::Null))
的字样。KeyGetter::Null
从KeyGetter
继承。提取一个“接口”并期望它。
class KeyGetter
module Interface
def to_key; end
def to_s; end
end
class Null
include KeyGetter::Interface
end
include Interface
sig {params(env_var_name: String).returns(KeyGetter::Interface)}
def self.from_env_var(env_var_name)
return Null.new if env_var_name.nil?
return new(env_var_name)
end
但是我想知道的(并且在文档中找不到)是:我可以描述鸭子的类型吗?就像我们在YARD中所做的一样,例如:
# @returns [(#to_s, #to_key)]
或者这是一个天生有缺陷的想法(因为理想情况下,我们也需要注释一下duck类型的方法。这样做时不要在语法上迷失方向。)
是的,我们可以在这里内嵌鸭子类型吗?如果没有,我们应该怎么做?
答案 0 :(得分:2)
但是我想知道的(并且在文档中找不到)是:我可以描述鸭子的类型吗?就像我们在YARD中所做的一样,例如:
我发现sorbet对具有特定键(称为流程"sealed object"的哈希)的支持非常有限。您可以尝试类似的方法,但是foo
将被识别为T::Hash[T.untyped, T.untyped]
,或者最多是T::Hash[String, String]
。
extend T::Sig
sig { returns({to_s: String, to_key: String}) }
def foo
T.unsafe(nil)
end
T.reveal_type(foo)
foo.to_s
foo.to_key
他们尝试使用Typed Struct([T::Struct]
)解决此问题,但这与您自己定义类/接口没有什么不同。
Sorbet确实支持元组,但这也不是理想的选择。 See on Sorbet.run
或者这是一个天生有缺陷的想法(因为理想情况下,我们也需要注释一下duck类型的方法。这样做时不要在语法上迷失方向。)
鉴于您要注释鸭子类型的方法,因此为它定义一个类就变得更加重要。在您概述的方法中,我最喜欢选项(2)。
您也可以改为使NULL为常量。但是考虑到当前代码的实现方式,它可能不如选项(2)
KeyGetter::NULL = KeyGetter.new(nil)