首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何指导Scala不要渲染抽象类型?

如何指导Scala不要渲染抽象类型?
EN

Stack Overflow用户
提问于 2017-02-27 22:17:27
回答 2查看 273关注 0票数 1

考虑到斗牛犬:

代码语言:javascript
复制
trait Animal {
  type Food

  def defaultFood(): Food
}
class Bulldog extends Animal {
  type Food = Steak

  ... implementations ...
}

Bulldog.defaultFood()函数对于编译器来说工作得很好(虽然我的语法高亮显示器出现了一个错误,但这并不是什么大问题):

代码语言:javascript
复制
val bulldog = new Bulldog()
val df: bulldog.Food = bulldog.defaultFood()

然而,如果斗牛犬被关在另一个类中,所有的地狱都会散开:

代码语言:javascript
复制
class Kennel(val animal: Animal) {
}
def getSupply(kennel: Kennel): kennel.animal.Food = {
  ... implementation ...
}

val kennel = new Kennel(bulldog)
val df2: bulldog.Food = getSupply(kennel)

Scala编译器将引发编译错误:

代码语言:javascript
复制
type mismatch;
 found   : Option[kennel.animal.V] where val kennel: Kennel
 required: bulldog.Food

Scala中目前缺少此功能吗?有什么办法让它起作用吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-27 23:29:00

您的代码有一个编译问题-- kennel.animal是无法解决的,因为类Kennel没有将animal公开为公共字段;通过在animal前面添加val很容易解决这个问题。

然而,似乎困扰你的是,Kennel对底层动物一无所知,只知道它是Animal。经过一只斗牛犬被认为是经过了一些动物。

尝试向Kennel添加更多类型信息

代码语言:javascript
复制
class Kennel[A <: Animal](val animal: A) {  }

def getSupply[A <: Animal](kennel: Kennel[A]): kennel.animal.Food

val kennel = new Kennel(bulldog)
val df2: bulldog.Food = getSupply(kennel)

现在Kennel知道了animal的确切类型(例如Bulldog),getSupply能够为这种动物返回确切的食物类型。

下面是您可以试用的完整工作代码:

代码语言:javascript
复制
trait Steak {
  override def toString() = "steak"
}

trait Animal {
  type Food
  def defaultFood(): Food
}

class Bulldog extends Animal {
  type Food = Steak
  def defaultFood() = new Steak {}
}

class Kennel[A <: Animal](val animal: A)

object Test extends App {

  def getSupply[A <: Animal](kennel: Kennel[A]): kennel.animal.Food = kennel.animal.defaultFood()

  val bulldog = new Bulldog()
  val kennel = new Kennel(bulldog)
  val df2: bulldog.Food = getSupply(kennel)

  println(df2) // prints "steak"
}
票数 3
EN

Stack Overflow用户

发布于 2017-02-28 21:16:40

参数多态(即类型多态性)是一种较好的建模方法。这里的主要操作是,你有一只动物,你必须检索它最喜欢的食物的一个实例。把它变成一个典型的例子,为特定的动物和他们喜欢的食物提供实例。例如:

代码语言:javascript
复制
@annotation.implicitNotFound(
  "Couldn't confirm that ${Animal}'s favourite food is ${Food}")
trait DefaultFood[Animal, Food] { def apply(animal: Animal): Food }
object DefaultFood {
  /** Helper to easily implement typeclass instances. */
  class Impl[Animal, Food](getFood: Animal => Food)
    extends DefaultFood[Animal, Food] {
    override def apply(animal: Animal): Food = getFood(animal)
  }
}

class Bulldog
object Bulldog {
  type Steak = String // Or whatever.

  implicit val defaultFood: DefaultFood[Bulldog, Steak] =
    new DefaultFood.Impl(_ => "Steak")
}

class Kennel[Animal, Food](
  animal: Animal)(implicit defaultFood: DefaultFood[Animal, Food]) {
  def getSupply: Food = defaultFood(animal)
}

object Test {
  val kennel = new Kennel(new Bulldog) // Kennel[Bulldog, Bulldog.Steak]
}

这会将泛型类型转发到Kennel类中,但由于Scala的类型推断,实际上不必详细说明这些类型。此外,如果没有特定动物及其食物的类型实例,@implicitNotFound注释将为您提供一个很好的编译错误消息。

请注意,AnimalFood类型实际上不需要是动物和食物;这正是我们在这里使用的语义。如果您以最通用的方式来看它,这个类型实际上只是一些A => BB类型的函数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42496800

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档