Scala:通过 if 语句更正表示类型的类型推断

2023-12-04

这是后续two 问题关于表示类型,它们是特征的类型参数,旨在表示有界类型成员(或类似的东西)底层的类型。我已经成功创建了类的实例,例如ConcreteGarage,有实例cars有界类型成员CarType.

trait Garage {
  type CarType <: Car[CarType]
  def cars: Seq[CarType]

  def copy(cars: Seq[CarType]): Garage

  def refuel(car: CarType, fuel: CarType#FuelType): Garage = copy(
    cars.map {
      case `car` => car.refuel(fuel)
      case other => other
    })
}

class ConcreteGarage[C <: Car[C]](val cars: Seq[C]) extends Garage {
  type CarType = C
  def copy(cars: Seq[C]) = new ConcreteGarage(cars)
}

trait Car[C <: Car[C]] {
  type FuelType <: Fuel
  def fuel: FuelType

  def copy(fuel: C#FuelType): C

  def refuel(fuel: C#FuelType): C = copy(fuel)
}

class Ferrari(val fuel: Benzin) extends Car[Ferrari] {
  type FuelType = Benzin
  def copy(fuel: Benzin) = new Ferrari(fuel)
}

class Mustang(val fuel: Benzin) extends Car[Mustang] {
  type FuelType = Benzin
  def copy(fuel: Benzin) = new Mustang(fuel)
}

trait Fuel
case class Benzin() extends Fuel

我可以轻松创建实例Cars like Ferraris and Mustangs 并将它们放入ConcreteGarage,只要简单:

val newFerrari = new Ferrari(Benzin())
val newMustang = new Mustang(Benzin())

val ferrariGarage = new ConcreteGarage(Seq(newFerrari))
val mustangGarage = new ConcreteGarage(Seq(newMustang))

但是,如果我只是根据标志返回其中一个,并尝试将结果放入车库,则会失败:

val likesFord = true
val new_car = if (likesFord) newFerrari else newMustang

val switchedGarage = new ConcreteGarage(Seq(new_car)) // Fails here

开关单独工作正常,它是调用ConcreteGarage构造函数因相当神秘的错误而失败:

error: inferred type arguments [this.Car[_ >: this.Ferrari with this.Mustang <: this.Car[_ >: this.Ferrari with this.Mustang <: ScalaObject]{def fuel: this.Benzin; type FuelType<: this.Benzin}]{def fuel: this.Benzin; type FuelType<: this.Benzin}] do not conform to class ConcreteGarage's type parameter bounds [C <: this.Car[C]]
val switchedGarage = new ConcreteGarage(Seq(new_car)) // Fails here
                     ^

我试过把那些魔法[C <: Car[C]]表示类型参数无处不在,但没有成功找到神奇的地方。


没有任何有用的超类型Ferrari and Mustang可以使用别名。你需要用这种方法把世界从里到外包裹起来。

一种可能性是添加Garage构建作为一种方法Car.

另一种可能性是定义一些负责生产兼容汽车和车库的“世界”:

trait World {
   type CarType <: Car[CarType]
   def newCar() : CarType
   def newGarage(cars: Seq[CarType]) = new ConcreteGarage[CarType](cars)
}

class FerrariWorld extends World {
   type CarType = Ferrari
   def newCar() = new Ferrari(Benzin())
}

class FordWorld extends World {
   type CarType = Mustang
   def newCar() = new Mustang(Benzin())
}

def play(world: World) {
   val car = world.newCar()
   println(car)
   val gar = world.newGarage(Seq(car))
   println(gar)
}

def test(likesFord: Boolean) {
   val w = if(likesFord) new FordWorld else new FerrariWorld
   play(w)
}

test(true)
test(false)

你会发现这可能会让人产生幽闭恐惧症。所以这实际上取决于您的目标场景。路径依赖类型总是会导致未来的约束。考虑这个带有类型参数的相当简单的变体:

trait Fuel { def liters: Int }
trait Make { def color: String }

case class Benzin(liters: Int = 0) extends Fuel
case class Diesel(liters: Int = 0) extends Fuel
case class Ferrari(color: String) extends Make
case class Mustang(color: String) extends Make { def race() { println( "Rrrroar" )}}

case class Car[M <: Make, F <: Fuel](make: M, fuel: F) {
   def refuel(f: F): Car[M, F] = copy(make, f)
}

case class Garage[M <: Make](cars: Seq[Car[M,_]] = Seq.empty) {
   def add(c: Car[M,_]) = copy(cars :+ c)
   def remove(c: Car[M,_]) = copy(cars.filterNot(_ == c))
   def refuel[F <: Fuel](c: Car[M,F], f: F) = copy( cars.map {
      case `c` => c.refuel(f)
      case other => other
   })
}    

val g0 = Garage[Mustang]()
val m  = Car(Mustang("black"), Benzin())
val f  = Car(Ferrari("red"), Benzin())
val g1 = g0.add(f)                // forbidden
val g1 = g0.add(m)                // ok
val g2 = g1.refuel(f, Benzin(45)) // forbidden
val g2 = g1.refuel(m, Diesel(45)) // forbidden
val g2 = g1.refuel(m, Benzin(45)) // ok
g2.cars.foreach(_.make.race())    // ok

结论:不要迷失方向……

enter image description here

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala:通过 if 语句更正表示类型的类型推断 的相关文章

  • Scala:解决“非法循环引用”

    我正在尝试实现一个基于 HashMap 的树 它支持给定根键的 O 1 子树查找 为了实现这个目标 我正在努力做到以下几点 scala gt type Q HashMap Char Q
  • scala 贷款模式,可选函数参数

    我有一个贷款模式 该模式应用函数 n 次 其中 i 是递增变量 偶尔 我希望传入的函数能够访问 i 但我不想要求传入的所有函数都需要定义一个参数来接受 i 下面的例子 def withLoaner n Int gt op Int gt St
  • 如何将 JSON 转换为 Scala 中的类型

    我的问题是我收到来自 twitter 的 JSON 文本 然后我想将此文本转换为 scala 中的本机对象 有标准方法可以做到这一点吗 我也在用Play 2 这是我所拥有的 import scala io Source fromInputS
  • Maven SBT 依赖工件?

    我同时使用 Maven 和 SBT 管理我的项目 其原因有 Intellij IDEA无法导入SBT 项目 idea sbt 插件没有 工作得很好 我不知道如何获得来源和 来自 SBT 的 javadocs 我想看到有关此问题的任何答案 问
  • Scala API 2.10.*:Function2.and然后发生了什么?

    我正在阅读 Joshua Suereth 所著的 Scala in Depth 我购买这本书是为了了解作者的明确能力 我在第 3 页上 在出现一堆拼写错误和不连贯的格式之后 好吧 我已经开始容忍这些错误 我偶然发现了以下示例 该示例涉及解决
  • scala 生成的字节代码如何删除已检查的异常?

    是否可以为应该抛出检查异常的方法编写字节代码 例如 除非该方法声明它抛出已检查的异常 否则以下 Java 类不会编译 public class CheckedExceptionJava public Class
  • 获取有关 Groovy 函数的信息(名称、签名、主体代码)

    我有一个 Groovy 文件 其中包含一堆简单的函数 如下所示 useful functions def myFunc1 String arg println Hello arg def myFunc2 String arg println
  • SBT:具有不同依赖项的两个 Scala 版本的交叉构建项目

    我有以下用例 我想为 scala 2 10 和 2 12 构建相同的 Scala 项目 这样做时 我想指定所提供的 2 10 版本的一些依赖项 而我希望将这些依赖项编译到 2 12 的 jar 中 我正在查看 SBT 的文档 发现如何分割b
  • 为什么scala不允许在trait中定义lazy val?

    我尝试用a来定义一个特质lazy val trait MyTrait lazy val something Int object SomeThing extends MyTrait override lazy val something I
  • 当我在 scala 中使用全局映射变量而不广播时会发生什么

    在 scala 中 当我在 scala 中使用全局映射变量而不进行广播时会发生什么 例如 如果我使用变量collect 例如collectAsMap 看来它是一个全局变量 我可以在所有地方使用它RDD mapValues 函数无需显式广播它
  • 缓存隐式解析

    为了减少项目的编译时间 我缓存了通过隐式查找解析的某些类型类 但这看起来有点麻烦 因为直接的实现不起作用 scala gt implicit val x String implicitly String x String null 隐式查找
  • 如何将枚举绑定到 playframework 表单?

    我有一个以下形式的枚举 object MatchFilterType extends Enumeration type MatchFilterType Value val gt Value gt val lt Value lt val eq
  • 生成 k 个成对独立的哈希函数

    我正在尝试实施一个计数最小草图 http en wikipedia org wiki Count Min sketchScala中的算法 所以我需要生成k个成对独立的哈希函数 这是一个比我以前编写过的任何东西都低的级别 除了算法类之外 我对
  • 从 Monoids 的 HList 类型派生 0 的 HList

    我正在学习 Shapeless 目前我正在尝试创建一个执行以下操作的函数 给定一个类型HList它返回HList of Nones 与Option对应于给定的类型HList type 例如 create String Int HNil re
  • 当恰好有一个选项非空时执行某项操作

    如果两个选项之一非空 我想计算一些东西 显然这可以通过模式匹配来完成 但是有更好的方法吗 o1 o2 match case Some o None gt Some compute o case None Some o gt Some com
  • Scala 中简单表达式的非法开始

    我刚刚开始学习scala 在尝试实现递归函数时 我在 Eclipse 中收到错误 简单表达式的非法开始 def foo total Int nums List Int if total nums sorted head 0 0 else r
  • 抽象类型与类型参数

    在什么情况下抽象类型应该优先于类型参数 添加到我的之前关于抽象类型与参数的回答 https stackoverflow com questions 1154571 scala abstract types vs generics 11547
  • scala 中“迭代 Seq 或如果为空”的更好版本?

    是否有更短 更好的方法来执行以下操作 mySeq map elmt gt do stuff if mySeq isEmpty some other stuff Ps 我正在使用 PlayFramework 这意味着在模板中使用 所以如果我错
  • 我需要比较两个数据帧以进行类型验证并发送非零值作为输出

    我正在比较两个数据帧 基本上 这些是两个不同数据源的模式 一个来自 hive 另一个来自 SAS9 2 我需要验证两个数据源的结构 因此我将模式转换为两个数据帧 它们是 SAS 架构将采用以下格式 scala gt metadata sho
  • 如何列出Resources文件夹中的所有文件(java/scala)

    我正在编写一个函数 需要访问资源中的文件夹 并循环遍历所有文件名 如果这些文件符合条件 则加载这些文件 new File getClass getResource images sprites getPath listFiles 返回空指针

随机推荐