inheritance - Scala函数的方差和覆盖

标签 inheritance scala overriding variance

我在理解重载时方法的变化方面遇到了一些问题。

尽管由于返回类型的协方差,这非常有效

class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(): Bla = new Bla
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(): Fasel = new Fasel                                      
}

即使函数在它们之间是互变的,此函数也会失败
参数类型。
class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(a: Fasel): Bla = new Bla                                           
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(a: Bla): Fasel = new Fasel
}

我这是怎么了?有指针吗?

问候,
雷乔

最佳答案

这里有两件事:

  • 函数和方法are not the same thing
  • 方法的参数类型不是多态的

  • 您的tester方法是一种方法,而不是Function1。可以使用下划线语法将其提升为一个函数:
    val f = (new FooTest[String]).tester _ // Fasel => Bla
    

    此函数的输入类型将是反变的。 (不过,值得一提的是,函数无法参数化,也必须说我必须拥有FooFooTest的实例才能获取tester方法的函数对象。这当然是从第一次观察中得出的!)

    函数是一个对象,它不能被覆盖,因为这没有任何意义。方法可以被覆盖。但是,如上所述,在方法的参数类型中,重写不是多态的。因此,例如:
    class A {
      def foo(a : Any) = println("A: " + a)
    }
    
    class B extends A {
      override def foo(s : String) = println("B " + s) //will not compile!
    }
    

    在我上面的示例中,这两个方法是两个单独的方法:动态分配仅在方法目标(即在其上被调用的对象)上起作用。

    在上面的示例中,如果删除了override声明,则代码将被编译。如果运行以下命令:
    (new B).foo(1)   //prints A 1
    (new B).foo("s") //prints B s
    

    这是因为,尽管这两种方法都称为foo,但它们是完全不同的方法(即,我已重载了foo,但未覆盖它)。最好的理解是方法的参数(包括它们的类型)构成该方法唯一名称的一部分。仅当一种方法具有完全相同的名称时,它才会覆盖另一种方法。

    从本质上讲,您已经混淆了您的问题中的和无关的两件事是什么,为了清楚起见,我将其简化为:
  • Function1上的方差注释定义了一个函数成为另一个函数的子类型(并因此可分配给给定类型的引用)的含义。
  • 方法可以在子类上覆盖,语言规范概述了何时发生此类覆盖的规则。
  • 关于inheritance - Scala函数的方差和覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4297019/

    相关文章:

    java - 在泛型中使用继承的有问题的声明

    C++ 运算符重载和继承

    scala - SBT中任务和命令的异同

    javascript - 覆盖 console.log 时如何显示 Promise 对象的状态和值

    c# - 如何在 C# 中覆盖 default(T)?

    php - Joomla 2.5 分页覆盖

    c++ - 如何更改子类方法中的参数?

    c++ - 访问基类对象中的 protected 成员

    spring - 如何将 ScalaTest 与 Spring 集成

    scala - Akka future - 并行与并发?