示例代码:
# 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
。 提取一个“接口(interface)”并期待它。
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 类型的方法。这样做时不要迷失在语法中)。
那么,是的,我们可以在此处内联注释 duck 类型吗?如果不是,我们应该怎么做?
最佳答案
But what I'd like to know (and didn't find in the docs) is: can I describe the duck type? Like we can do in YARD, for example:
我发现 sorbet 对具有特定键的散列的支持非常有限(流称为 "sealed object" )。您可以尝试这样的操作,但 foo
将被识别为 T::Hash[T.untyped, T.untyped]
,或者至多为 T::哈希[字符串,字符串]
。
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]
),但这与您自己定义类/接口(interface)没有什么不同。
Sorbet 确实支持元组,但在这里也不理想。 See on Sorbet.run
Or is it an inherently flawed idea (because ideally we need to annotate the duck type's methods too. And not get lost in syntax while doing that).
既然要注解duck类型的方法,那就更需要为它定义一个类了。在您概述的方法中,我最喜欢选项 (2)。
您也可以将 NULL 设为常量值。但是考虑到当前代码的实现方式,它可能不如选项 (2) 好
KeyGetter::NULL = KeyGetter.new(nil)
关于ruby - 我可以在方法签名中指定鸭子类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56703466/