我具有以下特征:
trait Storage[C <: Config] {
def get(name: String, version: Int): Option[C]
def list: List[(String, String)]
def register(config: C): Boolean
}
我想创建以下类:
class MultiStorage[C <: Config](storages: List[Storage[_ <: C]]) extends Storage[C] {
def get(name: String, version: Int): Option[C] = {...}
def list: List[(String, String)] = {...}
def register(config: C) = {...}
如果不清楚,其含义是MultiStorage
在多个存储中存储类型为C
(或子类型)的元素,每个存储中都包含一种类型的元素。
我正在与泛型作斗争以实现register方法。这个想法是,根据我要注册的对象的类型,我需要选择合适的存储空间进行注册,例如:
def register(config: C) = {
storages.foreach(s => {
if (typeOf(s) is Storage[C]) { // same type of config
s.register(config)
return
}
})
}
我尝试了泛型和类型标记,但是在这里没有什么有用的共享。我可能以为我需要添加另一个类型标签来区分我在寄存器中收到的内容和声明为存储类型的内容。
我尝试过的想法之一是在Storage
中有一个返回类型的方法:
protected def getType()(implicit tag: TypeTag[C]): universe.Type = typeOf[C]
但是在呼叫方,我却得到了类似_$1
之类的结果,老实说我不明白这意味着什么。
另一种尝试是使用shapeless
,但是在这种情况下,我不确定HList
存储中是否可以有一个包含任意数量元素的多存储
答案 0 :(得分:2)
需要使运行时类可用,例如:
class Config
class FooConfig extends Config
class BarConfig extends Config
trait Storage[C <: Config] {
val ctag: ClassTag[C]
def get(name: String, version: Int): Option[C]
def list: List[(String, String)]
def register(config: C): Boolean
}
class FooStorage(implicit val ctag: ClassTag[FooConfig]) extends Storage[FooConfig] {
override def get(name: String, version: Int): Option[FooConfig] = ???
override def list: List[(String, String)] = ???
override def register(config: FooConfig): Boolean = ???
}
class BarStorage(implicit val ctag: ClassTag[BarConfig]) extends Storage[BarConfig] {
override def get(name: String, version: Int): Option[BarConfig] = ???
override def list: List[(String, String)] = ???
override def register(config: BarConfig): Boolean = ???
}
class MultiStorage[C <: Config](storages: List[Storage[_ <: C]])(implicit val ctag: ClassTag[C]) extends Storage[C] {
def get(name: String, version: Int): Option[C] = ???
def list: List[(String, String)] = ???
def register(config: C): Boolean = {
storages.foreach(storage => {
if (storage.ctag.runtimeClass.isAssignableFrom(config.getClass)) {
}
})
???
}
}
由于特征不能具有构造函数参数,因此在实现该特征的每个类中都需要重复使用隐式类标记。如果您的类结构允许Storage
成为抽象类,则可以减少样板数量:
abstract class Storage[C <: Config](implicit val ctag: ClassTag[C]) {
def get(name: String, version: Int): Option[C]
def list: List[(String, String)]
def register(config: C): Boolean
}
class FooStorage extends Storage[FooConfig] {
override def get(name: String, version: Int): Option[FooConfig] = ???
override def list: List[(String, String)] = ???
override def register(config: FooConfig): Boolean = ???
}
答案 1 :(得分:0)
使用Shapeless的可能方法是
import shapeless.{::, HList, HNil}
object App {
trait Config
object config1 extends Config
object config2 extends Config
trait Storage[C <: Config] {
def get(name: String, version: Int): Option[C]
def list: List[(String, String)]
def register(config: C): Boolean
}
object storage1 extends Storage[config1.type] {
override def get(name: String, version: Int): Option[config1.type] = ???
override def list: List[(String, String)] = ???
override def register(config: config1.type): Boolean = {
println("storage1#register")
true
}
}
object storage2 extends Storage[config2.type] {
override def get(name: String, version: Int): Option[config2.type] = ???
override def list: List[(String, String)] = ???
override def register(config: config2.type): Boolean = {
println("storage2#register")
true
}
}
class MultiStorage[L <: HList](storages: L) /*extends Storage[C]*/ {
// def get(name: String, version: Int): Option[C] = ???
def list: List[(String, String)] = ???
def register[C <: Config](config: C)(implicit find: Find[C, L]): Boolean = find(config, storages).register(config)
}
trait Find[C <: Config, L <: HList] {
def apply(config: C, l: L): Storage[C]
}
trait LowPriorityFind {
implicit def tail[C <: Config, L <: HList, C1 <: Config, T <: HList](implicit
ev: L <:< (Storage[C1] :: T),
find: Find[C, T]): Find[C, L] = (config, l) => find(config, l.tail)
}
object Find extends LowPriorityFind {
implicit def head[C <: Config, L <: HList, T <: HList](implicit
ev: L <:< (Storage[C] :: T)): Find[C, L] = (_, l) => l.head
}
val multiStorage = new MultiStorage(storage1 :: storage2 :: HNil)
def main(args: Array[String]): Unit = {
multiStorage.register(config1) // storage1#register
multiStorage.register(config2) // storage2#register
}
}
使MultiStorage
扩展Storage
可能会限制太多。我们可以写
class MultiStorage(storages: List[Storage[_ <: Config]] /*i.e. List[Storage[T] forSome { type T <: Config}]*/)
extends Storage[T forSome { type T <: Config }] /*i.e. just Storage[Config]*/
即Storage
的某个未知类型T <: Config
。但是由于我们可以注册任何类型的T <: Config
配置,因此如果Scala中存在这样的语法,但实际上Scala没有rank-2 types,则应该更像Storage[T forAll { type T <: Config }]
或Storage[[T <: Config]T]
。 / p>