wiki Contravariant_method_argument_type表示重写方法将子类型规则作为函数类型,但除了一个支持逆变量参数类型之外没有其他语言。我也无法想出使用它的任何好处。
示例:
class AnimalShelter {
Animal getAnimalForAdoption() { ... }
void putAnimal(Animal animal) { ... }
}
class CatShelter extends AnimalShelter {
@Overriding
Cat getAnimalForAdoption() { return new Cat(); }
@Overriding
void putAnimal(Object animal) { … }
}
我的问题是:
答案 0 :(得分:7)
翻译的示例重写方法的逆变参数类型是否有用?如果是的话,它在哪里?
interface Carnivore {
void eat(Meat food);
}
interface Herbivore {
void eat(Plant food);
}
interface Omnivore extends Carnivore, Herbivore {
// overrides both above eat methods,
// since Meat and Plant are subtypes of Food
void eat(Food food);
}
方法是一个功能吗?
在Scala?不,但它可以转换为函数。
为什么Scala对函数类型和覆盖方法类型有不同的规则?
因为重写方法类型必须遵循JVM的规则。 可以通过创建桥接方法来完成(在上面的例子中,添加方法eat(Plant)
和eat(Meat)
只调用eat(Food)
),类似于协变返回的方式类型是实现的,但它会增加语言的复杂性而没有太大的好处。
答案 1 :(得分:3)
我还可以从Spray工具包添加一个示例,特别是Marshaller特征。一般来说,您可以将Marshallers视为一个函数,将T
类型的实体转换为HttpEntity
(对于http响应),但有一些内部技巧,所以实际上它实现为(T, Context) => Unit
,HttpEntity
生成Contenxt
。无论如何,如果你看一下它的声明,你会发现它的类型T
处于逆变位置:
trait Marshaller[-T] {
def apply(value: T, ctx: MarshallingContext)
}
从语义上讲,您可以根据返回Unit
的简单函数来思考。这里的逆差是自然的。假设您有一个简单的层次结构:
sealed trait ServerInfo {
def data: DataTime
}
case class ServiceStatus(status: String, data: DateTime = DateTime.now) extends ServerInfo
有了这个封士:
val serverInfoMarshaller: Marshaller[ServerInfo] = ???
val serverStatusMarshaller: Marshaller[ServerStatus] = ???
你有一个返回这个状态的功能:
def response(data: ServiceStatus, marshaller: Marshaller[ServiceStatus]): Unit = ???
但是因为marshaller是逆变的,你不仅可以使用serverStatusMarshaller: Marshaller[ServerStatus]
,还可以使用serverInfoMarshaller: Marshaller[ServerInfo]
,因为它也知道如何将ServerStatus
序列化为用户的正确响应。 / p>