如何解决结构鸭子类型是否与 LSP 兼容?
在某些情况下,结构子类型是否会导致无法使用 LSP?例如,假设我有一个 Python* 设置,其标称类型为
class Foo(ABC):
def frobnicate(self) -> int:
""" frobnicate in a general fashion """
class SubFoo(Foo):
def frobnicate(self) -> int:
""" frobnicate in a particular fashion """
def bar(f: SubFoo) -> int:
return f.frobnicate()
我可以在 bar
中确定我有一个 SubFoo
并且由于 LSP 我知道调用它会“以特定的方式frobnicate”。这一切都很好。现在假设我改用结构子类型(注意 Protocol
)
class Foo(Protocol):
def frobnicate(self) -> int:
""" frobnicate in a general fashion """
class SubFoo(Foo,Protocol):
def frobnicate(self) -> int:
""" frobnicate in a particular fashion """
def bar(f: SubFoo) -> int:
return f.frobnicate()
我不能确定在 bar
我有一个 SubFoo
因为一个 Foo
也满足那个协议,所以我可能,天堂禁止,“以一般方式frobnicate” .也就是说,LSP 不适用,因为子类型和超类型之间没有区别。
*我以 Python 为例,因为这就是我所知道的。这是一个语言不可知的问题,但我意识到这可能是由于 Python 的细节
解决方法
LSP 是一致性声明,而不是实现。
子类型要求:令 ϕ(x) 是一个关于类型 T 的对象 x 的可证明属性。那么对于类型 S 的对象 y,ϕ(y) 应该为真,其中 S 是 T 的子类型。
请注意,LSP 仅涉及一般的类型和子类型,而不是名义、结构或其他特定的子类型。
转述,可以说“无论类型保证什么,它的子类型也必须保证”。由于结构类型仅与结构有关 – 表示为类型保证 – 这一点很容易满足。
结构类型仅根据结构定义子类型。例如,Foo
定义了结构类型:
{frobnicate: (Self) -> int}
值得注意的是,这表示 frobnicate
存在,采用 Foo
并返回 int
。它没有说明这是如何发生的,或者输入和输出之间有什么关系。
重要的是,Foo
并未以一般或特定方式说明是 frobnicate
。实现、文档字符串或类似内容不是类型的一部分。
同样,SubFoo
定义了完全相同的结构类型:
{frobnicate: (Self) -> int}
就 LSP 而言,替换 SubFoo <: Foo
和 Foo <: SubFoo
都是有效的:Foo
和 SubFoo
仅在未捕获方式上有所不同通过结构类型,因此不能由任何一种类型保证。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。