【问题标题】:Is there are way to create a generic class with a trait or mixin that is a subtype of the type parameter有没有办法创建一个具有作为类型参数子类型的 trait 或 mixin 的泛型类
【发布时间】:2017-05-04 20:51:07
【问题描述】:

我正在尝试将额外数据附加到其他类型,并且具有类似于以下的特征:

trait ExtraData {
  def getExtraData() : Array[Byte]
}

我目前正在这样使用它:

class ExternalType1WithExtraData(superType:ExternalType1, bytes:Array[Byte]) extends ExternalType1(superType.a,superType.b, ...) with ExtraData {
  def getExtraData() : Array[Byte] = bytes
}

class ExternalType2WithExtraData(superType:ExternalType2, bytes:Array[Byte]) extends ExternalType2(superType.z,superType.w, ...) with ExtraData {
  def getExtraData() : Array[Byte] = bytes
}

似乎有一种通用的方法可以创建这些类,但我还没有找到。

--- 开始编辑 -- 添加所需的行为

给定一个函数

def sendData(ex : ExternalType1)

我希望能够将我的增强类型传递给该函数。

val data:ExternalType1 = ???
val moredata:ExternalType1 = { new ExternalType1 with ExtraData{...} }
sendData(moredata)

--- 结束编辑

我试图按照这些思路做事,但没有成功:

// Compiler wont let me extend T
class WithExtraData[T](bytes:Array[Byte]) extends T with ExtraData{
  def getExtraData() : Array[Byte] = bytes
}

:12: 错误:需要类类型但找到 T 类 WithExtraDataT 使用 ExtraData{ 扩展 T ^ :12: 错误:非法继承; T超型 不是超类 Object 的子类 混合特性 ExtraData Class WithExtraDataT 用 ExtraData 扩展 T{

// Seems closer, but doesn't work.
class WithExtraData[T](t:T, bytes:Array[Byte]) extends ExtraData {
  this : T => t
  def getExtraData() : Array[Byte] = bytes
}

:13: 警告:纯表达式在语句位置不执行任何操作;多行表达式可能需要括号 自我:T => t ^ 定义类WithExtraData

scala> new WithExtraData[String]("hi", new ArrayByte) :13: 错误:无法实例化类 WithExtraData,因为它不符合其自身类型 WithExtraData[String] with String

有没有办法做到这一点?

【问题讨论】:

  • 我猜你忽略了一个重要的要求。您是否尝试扩展ExternalType1,以便可以将此实例传递给某个外部库,将其取回,转换为ExtraData,然后转换为getExtraData?如果没有,你绝对应该远离子类化。
  • 是的,我正在尝试做一些与此非常相似的事情,但对 Kryo 使用自定义序列化程序。

标签: scala generics traits scalaz type-constructor


【解决方案1】:

我认为您可以合理获得的最接近(至少没有宏)不是扩展ExternalType1,而是进行隐式转换:

class WithExtraData[T](val value: T, bytes: Array[Byte]) extends ExtraData {
  def getExtraData(): Array[Byte] = bytes
}

object WithExtraData {
  implicit def getValue[T](x: WithExtraData[T]): T = x.value
}

然后你可以例如只要需要ExternalType1,就传递WithExtraData[ExternalType1]

【讨论】:

  • 据我了解,这会导致“extraData”被扯掉而不是实际传递。
  • 不清楚您所说的“扯掉”是什么意思。我打算简单地建议 type WithExtraData[A] = (A, Array[Byte]) 作为对这个解决方案的进一步改进,但我相信这并不能解决你真正想要解决的问题。
  • 是的,我仍然希望能够将 WithExtraData[T] 传递给在 T 上运行的函数。
【解决方案2】:

如果我理解正确,您基本上会尝试使用由值表示的其他类型信息来丰富您的类型?在这种情况下,您要查找的概念称为Dependent Types

Scala 本身并不支持这个概念(例如 Idris)。但是,有一些解决方法可以更接近。

一个例子是使用 Shapeless

import shapeless._
import SingletonTypes._

val test1: ^((20 + 50) > 1) = true
test1: Boolean(true) = true

val test2: ^((20 + 50) > 1) = false
<console>:11: error: type mismatch;
 found   : Boolean(false)
 required: Boolean(true)

【讨论】:

  • 非常酷! - 但是我希望额外的数据是特定于实例的。
猜你喜欢
  • 1970-01-01
  • 2016-05-18
  • 1970-01-01
  • 2021-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多