Kotlin多态性 - 接收参数不能具有Overriden类型,但是返回论点可以?

发布于 2025-02-01 19:35:27 字数 1347 浏览 2 评论 0原文

也许我累了或没有直截了当,或者这只是我从未尝试过的事情。

我有一个基本数据类型,让我们称其为foo,然后将其称为问题,它揭示了与此foo一起使用的一些功能数据类型。

接口函数之一返回 a foo和functions recieves a foo之一。

然后,我从foo继承,为创建一个新的数据类型,让我们称其为bar,然后我实现问题接口,然后在覆盖,我将foo的类型覆盖为bar

对于返回 foo的函数,bar覆盖的用法工作。但是,对于接收 foo的函数,bar覆盖的用法不起作用:

open class Foo(
    open val name: String
)

interface Problem {
    fun setFoo(foo: Foo)
    fun getFoo() : Foo
}

data class Bar(
    override val name: String
) : Foo(
    name = name
)

class ProblemImpl : Problem {
    override fun setFoo(foo: Bar) {
        TODO("Not yet implemented")
    }

    override fun getFoo(): Bar {
        TODO("Not yet implemented")
    }
}

setfoo覆盖什么都没有覆盖

现在,这似乎很明显。只是不要超越这样的类型!您可以通过bar实例,由于多态性,它们将被接收为foo实例。但是,由于复杂的原因,我不会进入这里,我无法执行此操作(想想在图书馆中声明DAO接口,并用室内注释在使用应用程序中覆盖它...)

我想我可以将界面键入参数化。喜欢:

interface Problem<T: Foo> {
   fun setFoo(foo: T)
   fun getFoo() : T
}

实际上,我想我刚刚回答了自己的问题...我现在尝试使用模板,但由于房间注释处理器可能无法处理模板接口...无论如何,谁能告诉我为什么接收的函数不能用子类型超过子类型,而返回的函数可以?

Perhaps I'm tired or not thinking straight, or perhaps this is just something I've never tried before.

I have a base data type, let's call it Foo, and an interface, let's call this Problem which exposes some functions that work with this Foo data type.

One of the interface functions returns a Foo and one of the functions recieves a Foo.

Then, I inherit from Foo, to create a new data type, let's call it Bar, I then implement the Problem interface, and in the overrides, I override the type of Foo to be Bar.

For the function which returns the Foo, the usage of the Bar override works. However, for the function that receives the Foo, the usage of the Bar override does not work:

open class Foo(
    open val name: String
)

interface Problem {
    fun setFoo(foo: Foo)
    fun getFoo() : Foo
}

data class Bar(
    override val name: String
) : Foo(
    name = name
)

class ProblemImpl : Problem {
    override fun setFoo(foo: Bar) {
        TODO("Not yet implemented")
    }

    override fun getFoo(): Bar {
        TODO("Not yet implemented")
    }
}

setFoo overrides nothing

Now, it might seem obvious; just don't override the types like this! You can just pass Bar instances, and due to polymorphism, they will be received as Foo instances. But, for complicated reasons I won't go into here, I cannot do this (think declaring Dao interface in library, and overriding it in consuming app with Room annotations...)

I suppose I could have the interface be type parameterized... like:

interface Problem<T: Foo> {
   fun setFoo(foo: T)
   fun getFoo() : T
}

In fact, I think I've just answered my own question... I'll try with templating now, but I have a hunch it will fail at compile time as Room annotation processor might not be able to deal with template interfaces... in any case, can anyone tell me why the function that receives cannot be overriden with a subtype whilst the function that returns can?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

幻梦 2025-02-08 19:35:27

在任何情况下,谁能告诉我为什么接收到的功能不能以亚型超过子类型,而返回的功能可以?

liskov替代原理无论您在哪里使用foo,都应该能够使用栏。

让我们看一下两种情况:

  1. 函数getfoo()返回foo。在子类型中,您返回栏。由于每个栏都是一个foo(因为bar是foo的子类型),因此您可以在使用基本版本的每个地方使用覆盖版的getfoo() - 它总是返回foo(恰好是bar,特定的类型的foo)。一切都很好。
  2. 函数setFoo()接收一个foo。在亚型中,您希望它接受栏。现在,有人通过引用基本类型使用您的子类型。它们传递给setFoo()不是栏的foo。但是您的setFoo()在这种情况下,只接受bar。这意味着您不能使用子类代替基类,这违反了Liskov的替代原则,并导致整个子类崩溃的想法。因此,选择是让语言不允许子类代替foo接受标准。

您也可以在 nofollow noreferrer”> nofollow noreferrer“> covariance and contravariance 以便更多地探索该主题时可以探索该主题的更多信息用于代替其超级型。

in any case, can anyone tell me why the function that receives cannot be overriden with a subtype whilst the function that returns can?

The limitation arises as a consequence of Liskov substitution principle: if Bar is a subtype of Foo, you should be able to use a Bar wherever you use a Foo.

Let's look at the two situations:

  1. The function getFoo() returns Foo. In a subtype, you return Bar. Since each Bar is a Foo (as Bar is a subtype of Foo), you can use your overridden version of getFoo() in each place you use the base version - it always returns a Foo (which just happens to be Bar, a specific type of Foo). Everything works just fine.
  2. The function setFoo() receives a Foo. In a subtype, you want it to accept Bar. Now, someone is using your subtype through a reference of the base type. They pass to setFoo() a Foo which is not a Bar. But your setFoo() in this case only accepts Bar. This means you can't use your subclass in place of the base class, which violates Liskov substitution principle and causes the whole idea of subclassing to collapse. Therefore, the choice is for the language to not allow a subclass to accept Bar in place of Foo.

You can also read on covariance and contravariance for more exploration of the topic when subtypes can be used in place of their supertypes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文