我正在实现一个数据结构,并希望用户能够使用任何类型作为键,只要他提供一个合适的密钥类型包装它。我有这个关键类型的特征。我们的想法是从基类到键类型进行隐式转换,另一种方法是(实际上)只使用基类型。特征看起来像这样:
trait Key[T] extends Ordered[Key[T]] {
def toBase : T
// Further stuff needed for datastructure...
}
object Key {
implicit def key2base[T](k : Key[T]) : T = k.toBase
}
呼叫站点代码可能如下所示:
def foo[K <% Key[K]]( bar : Seq[K] ) = bar.sorted(0)
计划是K
类型的值应该隐式转换为有序的Key[K]
,或者Key[K]
上的排序应该分别使用,所以一切都应该解决。当然,没有办法在特征本身中实现隐式base2key
。或者在那里,也许使用隐式传递的类清单?考虑到这一点,我找不到任何参考。
是否有可能以某种方式断言断言任何延伸Key[T]
的类型都会带有隐式转换T => Key[T]
?遗憾的是,伴侣对象不能有抽象方法。
假设这样做,整个企业是否可行,或者所述用例是否需要多个链式隐式转换? (正如我所读到的那样,链接不会发生。)
附录:根据上述定义,我可以使用Node(key : K, ...)
对K <% Key[K]
(sortWith(_.key <= _.key)
下)的序列进行排序,但不使用sortBy(_.key)
}。显然,从K
到Key[K]
的转换是隐式发生的,即使我从未在任何地方声明它,但Ordering
上没有隐含的Key[K]
。这是怎么回事?
答案 0 :(得分:1)
你问“是否有可能以某种方式静态断言任何扩展Key[T]
的类型都会带有隐式转换T => Key[T]
?伴随对象不能有抽象方法,遗憾的是。”
但是你的例子是一个静态断言:当你需要从T
到Key[T]
的视图时,你在编译时断言你只能调用foo
来获取可以解除的类型钥匙。或者我误解了什么?
关于附录:你说你感到惊讶的是“从K
到Key[K]
的转换是隐含的,即使它从未在任何地方被我宣布过”。事情是,你确实声明了它:T <% Key[T]
(我在这里使用的是T
而不是K
,你似乎混淆了基础* T 的概念* ype和* K *在这里?)。这与
def foo[T](bar : Seq[T])(implicit view: T => Key[T]) = bar.sortWith(_ <= _)(0)
因此,当您执行sortWith(_ <= _)
时,您将T
强制转换为Key[T]
(根据特征<=
定义Ordered[Key[T]]
)。
以你的Node为例,为什么不这样做
case class Node[K](key: K)
def test[K](bar: Seq[Node[K]])(implicit ord: Ordering[K]) = bar.sortBy(_.key)(0)
希望有所帮助...
答案 1 :(得分:0)
以下是您问题的可能解决方案(希望我能正确理解您的要求):
// Key stuff
trait Keyable[T] {
def toKey(t: T): Key[T]
}
trait Key[T] extends Ordered[Key[T]] {
def toBase() : T
}
object Key {
implicit def key2base[T](k : Key[T]) : T = k.toBase
implicit def base2key[T : Keyable](k : T) : Key[T] = implicitly[Keyable[T]].toKey(k)
}
// more concrete stuff - namely A
class A(val i: Int) {
override def toString = "A {" + i + "}"
}
object A {
implicit val aKeyable = new Keyable[A] {
def toKey(t: A) = new Key[A] {
def toBase() = t
def compare(that: Key[A]) = t.i compare that.i
}
}
}
// testing
def foo[K : Keyable](bar: Seq[K]) = bar.sortBy(implicitly[Keyable[K]].toKey)
val list = List(new A(5), new A(1), new A(3))
println(foo(list)) // prints: List(A {1}, A {3}, A {5})
在这种情况下,Key[T]
是类型T
的包装,而Keyable[T]
是类型calss,允许将类型T
转换为Key[T]
。我还展示了base2key
的样子。
答案 2 :(得分:0)
在这个答案中,我将保留目前最好的版本以供参考。使用this answer更集中的问题;将根据this one以2.9的形式过时。
Key
特征保持不变;我添加了一个特定的功能用于说明:
trait Key[T] extends Ordered[Key[T]] {
def toBase : T
def foo(i : Int) : Key[T]
}
object Key {
implicit def key2base[T](k : Key[T]) : T = k.toBase
implicit def ordering[T <% Key[T]] = new Ordering[T]{
def compare(x: T, y: T) = x compare y
}
}
以下按预期工作(如果import Key._
已完成):
def min[K <% Key[K]](l : Seq[K]) : K = l.sorted.head
我们假设我们有一个简单的class Node[K](val key : K)
。事情再次发挥作用:
def min[K <% Key[K]](l : Seq[Node[K]]) : Node[K] = l.sortBy(_.key).head
再举一个例子,假设这段代码只使用Key[T]
接口:
def test[K <% Key[K]](bar : Seq[K]) =
bar.map(_.foo(3)).sorted
请注意,由于map
直接产生Seq[Key[K]]
,因此会进行编译;排序不需要转换。现在,如果我们正确实施Key
,请说
class StringKey(val key : String) extends Key[String] {
def foo(i : Int) = StringKey(this.key + "_" + i)
def toBase = key
override def compare(other : Key[String]) = -1*this.key.compare(other.toBase)
}
object StringKey {
def apply(key : String) = new StringKey(key)
def unapply(key : String) = Some(key)
implicit def string2key(s : String) = StringKey(s)
}
以下内容应该有效:
import StringKey.string2key
import Key.key2base
val bla : Seq[String] = test(Seq("b", "c", "a")).map(_.capitalize)
println(bla)
// expected output: Seq(C_3, B_3, A_3)
但实际上,找不到从StringKey
到String
的转换:
error: value capitalize is not a member of this.Key[java.lang.String]
这很奇怪; 是从Key[String]
到String
的转换,如果使用泛型类型参数声明的话。