如果结构类型中定义的方法' B'是结构类型的超集' A'为什么我不能通过' B'想要一个' A'?

时间:2015-10-23 04:19:20

标签: scala polymorphism duck-typing

我正在尝试使用类型变量和结构类型作为学习Scala' cake'图案。

下面是一个玩具API,说明了我的问题:

当结构类型中定义的方法' B'是那些人的超集 结构类型' A',为什么我不能将B的实例传递给想要' A'?

的方法
...  Toy API ....

object Tester extends App {

  trait SomeApi {
    type Organism <: {
      def die(): Unit;
    }

    type Dog <: {
      def die(): Unit;
      def bark(): Unit;
    }

    def dieQuietlyDoesntCompile(entity: Organism): Unit = {
      entity.die()
    }

   def dieQuietly(entity: { def die(): Unit }): Unit = {
      entity.die()
   }

    def processDog(dog: Dog): Unit = {
      println("start dog process on : " + dog)
      dieQuietly(dog)                            
    }
  }
}

我的API中的结构类型从您可能称之为“基本类型”的内容开始。 (以上例子中的生物),加上,我 在API中有其他类型扩展基类型。在Toy API的情况下,Dog拥有Organism的所有方法,以及 还有一个:&#39; bark()&#39;。

我想编写一些辅助方法来操作基类型,如图所示 processDog()方法....这需要一个&#39; Dog&#39;例如,但也想呼唤“悄悄地”#39;哪一个 处理更通用的类型&#39;有机体&#39;。

我上面做的事情的方式是有效的,但它真的很笨重,因为我必须完全重复所有的方法 基础结构类型。在这个玩具案例中并没有那么糟糕(因为我只有一个方法:die()),但是这些结构类型中的方法数量真的很尴尬 增加。

因此,我宁愿将dog实例传递给类似&#39; dieQuietlyDoesntCompile()&#39;的方法。
但是,正如函数名称所示,如果我将它传递给Dog实例,则无法编译错误:

  

类型不匹配;发现:dog.type(具有底层类型   SomeApi.this.Dog)需要:SomeApi.this.Organism

有人能建议更方便的方法来实现我的目标吗?或者我不能重复基类型中的方法? (这种方法对我来说似乎不太干)。在此先感谢您的帮助 ! /克里斯

2 个答案:

答案 0 :(得分:2)

您的问题是您使用绑定类型<:来定义DogOrganism。您使用die()方法将它们约束为类的子类,这使它们不相关。

让我用常规类型来说明它:

trait Mortal // suppose this trait is analogue of { def die():Unit }
class Organism extends Mortal
class Dog extends  Mortal

def die(o:Organism) {}

die(new Dog)  // obviously will not compile

通过定义Organism没有类型边界:

,可以轻松修复代码
  type Organism = {
    def die(): Unit;
  }

答案 1 :(得分:0)

扩大Aivean的答案:

  

当结构类型中定义的方法&#39; B&#39;是结构类型的超集者&#39; A&#39;为什么我不能将B的实例传递给想要&#39; A&#39;?

的方法?

你可以,但在这种情况下,他们不是。 Organism不是结构类型,它是一个抽象类型成员,需要是结构类型的子类型。 SomeApi的一种可能实现是

class ApiImpl extends SomeApi {

  type Organism = {
    def die(): Unit
    def live(): Unit
  }

  type Dog = {
    def die(): Unit
    def bark(): Unit
  }

  override def dieQuietlyDoesntCompile(entity: Organism): Unit = {
    entity.live()
  }
}

希望您能在Dog传递给dieQuietlyDoesntCompile这里的原因显而易见;但这也意味着你无法在原案件中通过它,或者你可以做到

 val api: SomeApi = new ApiImpl

 val dog: api.Dog = ...

 api.dieQuietlyDoesntCompile(dog)