函数的返回类型由其参数的类型成员定义

时间:2016-05-20 13:33:43

标签: scala

根据评论者(Miles和m-z)的反馈更新了我的问题:

我通过姓名或年龄找到重复的“值”。

sealed trait DuplicateResult 
case class DuplicatesByName(name: String, people: Set[String]) extends DuplicateResult
case class DuplicatesByAge(age: Int, people: Set[String]) extends DuplicateResult

根据姓名或年龄,返回类型必须不同:

sealed trait QueryByDuplicate {
  type DuplicateResultType
}

case class Name(name: String) extends QueryByDuplicate {
  override type DuplicateResultType = DuplicatesByName
}

case class Age(age: Int) extends QueryByDuplicate {
  override type DuplicateResultType = DuplicatesByAge
}   

然后,我定义了一个编译并运行的函数:

def findDupes(x: QueryByDuplicate): DuplicateResult = x match {
  case Name(n) => DuplicatesByName(n, Set("1", "2"))
  case Age(a)  => DuplicatesByAge(a, Set("42"))
}

scala> findDupes(Name("kevin"))
res0: DuplicateResult = DuplicatesByName(kevin,Set(1, 2))

scala> findDupes(Age(77))
res1: DuplicateResult = DuplicatesByAge(77,Set(42))

然而,type DuplicateResultType似乎很弱,因为我可以在那里添加任何类型。

请批评并改进我的实施。

1 个答案:

答案 0 :(得分:0)

选项1:结果类型信息在您的版本中丢失,因为调用者无法影响findDupes的固定结果类型。您可以使用泛型,以便调用者重新获得此控件:

sealed trait QueryByDuplicate[T <: DuplicateResult]
case class Name(name: String) extends QueryByDuplicate[DuplicatesByName]
case class Age(age: Int) extends QueryByDuplicate[DuplicatesByAge]

def findDupes[T <: DuplicateResult](x: QueryByDuplicate[T]): T = x match {
  case Name(n) => DuplicatesByName(n, Set("1", "2"))
  case Age(a) => DuplicatesByAge(a, Set("42"))
}
val dupes: DuplicatesByName = findDupes(Name("kevin"))

选项2:既然你也要求批评,我不认为你设计的方式是一种好的做法。有几个定义查询的类,以及不同位置的每个类的实现列表,难以维护。你可以使用好的旧多态:

  sealed trait QueryByDuplicate[T <: DuplicateResult] {
    def findDupes: T
  }
  class Name(name: String) extends QueryByDuplicate[DuplicatesByName] {
    override def findDupes: DuplicatesByName = DuplicatesByName(name, Set("1", "2"))
  }
  class Age(age: Int) extends QueryByDuplicate[DuplicatesByAge] {
    override def findDupes: DuplicatesByAge = DuplicatesByAge(age, Set("42"))
  }
  val dupes: DuplicatesByName = new Name("kevin").findDupes

这就是你可能会用Java做的。有时候,即使我们有新玩具,最好还是坚持旧的方式。

选项3:谈论instanceOf,这也有效:

  sealed trait QueryByDuplicate {
    type DuplicateResultType
  }
  case class Name(name: String) extends QueryByDuplicate {
    override type DuplicateResultType = DuplicatesByName
  }

  case class Age(age: Int) extends QueryByDuplicate {
    override type DuplicateResultType = DuplicatesByAge
  }

  def findDupes(x: QueryByDuplicate): x.DuplicateResultType = x match {
    case Name(n) => DuplicatesByName(n, Set("1", "2")).asInstanceOf[x.DuplicateResultType]
    case Age(a) => DuplicatesByAge(a, Set("42")).asInstanceOf[x.DuplicateResultType]
  }
  val dupes: DuplicatesByName = findDupes(Name("kevin"))

findDupes()在字节码中的返回类型为Object,但Scala足够聪明,可以推断出正确的类型。