假设我们有一个类似Pug : Dog : Mammal : Animal
的类层次结构。
我想要一个接受Bag<T>
(其中Bag
在T
中不变)参数的函数,该事物是Dog的子OR超类:fun work(things: Bag<in/out Dog)
{1}},Bag<Animal>
,Bag<Dog>
可以,但是Bag<Pug>
不被接受。
老实说,我什至不确定这种投影的类型。有指针吗?
答案 0 :(得分:1)
如果您想到in
和out
修饰符的真正含义,您很快就会意识到拥有in OR out
并没有任何意义。
我们首先来看一下out
。拥有<out T>
并不意味着“此函数接受T
及其子类作为参数”。它实际上意味着“此函数将不会对类T
的参数执行任何操作,或其任何子类都无法执行”。 此修饰符对您可以对该参数执行的操作施加限制。
检查此代码:
fun doThingsWithBag(bag: Bag<out Dog>) {
bag.getAny().walk() // allowed
bag.put(Dog()) // not allowed
}
您不允许将任何狗放入该袋中,因为该袋实际上可能是Bag<Pug>
类型,并且Bag<Pug>
不会接受随机的Dog
。
in
也是如此。 <in T>
并不意味着“此函数接受T
及其上级”。它更像是“此函数将不会执行任何操作T
,或其任何超类都无法执行”。
fun doThingsWithBag(bag: Bag<in Dog>) {
bag.put(Dog()) // allowed
bag.getAny().walk() // not allowed
}
现在您可以将狗放在包中了,但是您对狗放在包中实际上无法做任何事情,因为包实际上可能是Bag<Animal>
,并且不能保证您所“藏的东西”从书包中取出的是Dog
。
正如您所看到的,in
和out
可以做什么之间有明显的区别,因此它们不能共存。
即使另一个答案中建议的接口也不能帮上大忙,因为您的Animal
类还需要实现相同的接口,这意味着Cat
也可以访问该接口。解决的唯一方法是让您的work
方法接受Bag<Any>
并手动检查其通用类。
更新:
您要执行的操作在OOP中是不可能的。您要找的基本上是这样的:
update(Animal()) // allowed
update(Dog()) // allowed
update(Pug()) // allowed
update(Cat()) // not allowed (compile time error)
但是,编译器无法阻止您执行此操作:
val animal: Animal = Cat()
update(animal) // ???
您只能在运行时通过手动检查输入类型来执行类似的操作。
答案 1 :(得分:0)
老实说,我什至不确定这种投影的类型。有指针吗?
对我来说,您需要的是使用Interfaces ,方法是在定义Interface
方法的地方创建一个work
。这很好,因为它遵循Composition over Inheritance原则。
在那之后,让您要使用它的类实现该接口(例如class Dog : Mammal(), WorkInterface
),并且不要在您不想/不需要使用work
的那些中实现它。
还要让它们覆盖 work
方法。这样,您将可以在需要时在对象实例上调用work
方法。例如,您的代码应如下所示:
WorkInterface
界面:
interface WorkInterface{
fun work(foo:String) //add the parameters you need
}
在类似Dog
的类上使用接口:
//implementing and extending are done the same way in Kotlin, after the colon
class Dog : Mammal(), WorkInterface{
//define your attributes, methods etc..
//override all the methods defined in the interface
override fun work(foo: String){
//implement the specific code you want this to do
}
}
之后,您可以在Dog
之类的myDog.work("whatever")
实例上使用。