4

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) {      …        }     
}

我的问题是:

  1. 重写方法的逆变参数类型是否有用?如果是,它在哪里?
  2. 方法是函数吗?为什么 Scala 对函数类型和覆盖方法类型有不同的规则?
4

2 回答 2

10

重写方法的逆变参数类型是否有用?如果是,它在哪里?

从Sather 文档翻译的示例:

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 对函数类型和覆盖方法类型有不同的规则?

因为覆盖方法类型必须遵循 JVM 的规则。这可以通过创建桥接方法来完成(在上面的例子中,添加方法eat(Plant)eat(Meat)调用eat(Food)),类似于实现协变返回类型的方式,但它会增加语言的复杂性而没有太多好处。

于 2014-03-23T05:43:50.360 回答
3

我还可以从Spray工具包中添加一个示例,尤其是Marshaller trait。一般来说,您可以将 Marshallers 视为一个函数,它将某些类型的实体转换THttpEntity(用于 http 响应),但有一些内部技巧,所以实际上它被实现为(T, Context) => Unit,其中HttpEntity由 this 生成Contenxt。无论如何,如果您查看它的声明,您会发现它的类型T处于逆变位置:

trait Marshaller[-T] {
  def apply(value: T, ctx: MarshallingContext)
}

从语义上讲,您可以根据返回 a 的简单函数来考虑这一点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用户序列化为正确的响应。

于 2014-03-23T08:45:06.357 回答