2

我正在实现一个数据结构,并希望用户能够使用任何类型作为键,只要他提供了一个合适的键类型来包装它。我有这种键类型的特征。这个想法是从基类型到键类型进行隐式转换,反之则(实际上)只使用基类型。特征如下所示:

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在 trait 本身中实现隐式。或者是否存在,也许使用隐式传递的类清单?考虑到这一点,我找不到任何参考资料。

是否有可能以某种方式静态断言任何类型扩展Key[T]都将带有隐式转换T => Key[T]?可悲的是,伴生对象不能有抽象方法。

假设这可行,整个企业是否可行,或者所述用例是否需要多个链接的隐式转换?(正如我所读到的,链接不会发生。)

附录:Node(key : K, ...)有了上面的定义,我可以通过 using 对(下K <% Key[K])的序列进行排序sortWith(_.key <= _.key),但不能使用sortBy(_.key). 因此,显然,从Kto的转换是Key[K]隐式发生的,即使我从未在任何地方声明它,但没有OrderingonKey[K]隐式可用。这里发生了什么?

4

3 回答 3

1

你问“是否有可能以某种方式静态断言任何类型扩展Key[T]都会带有隐式转换T => Key[T]?可悲的是,伴生对象不能有抽象方法。”

但是您的示例是静态断言:当您需要从Tto的视图时Key[T],您在编译时断言您只能调用foo可以提升为键的类型。还是我误解了什么?

关于附录:您说您对“从Kto的转换Key[K]隐含地发生,即使我从未在任何地方声明过”感到惊讶。问题是,您确实声明了它:(T <% Key[T]我在T这里使用而不是K,您似乎在这里混淆了 base * T *ype 和 * K *ey 的概念?)。这与

def foo[T](bar : Seq[T])(implicit view: T => Key[T]) = bar.sortWith(_ <= _)(0)

因此,当您sortWith(_ <= _)强制执行TKey[T]<=根据 trait 定义Ordered[Key[T]])。

以你的节点为例,为什么不做

case class Node[K](key: K)
def test[K](bar: Seq[Node[K]])(implicit ord: Ordering[K]) = bar.sortBy(_.key)(0)

希望有帮助...

于 2011-01-28T21:06:34.737 回答
0

在这个答案中,我将保留当前最好的版本以供参考。使用这个答案来解决更集中的问题;根据这个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产生 a 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)

但实际上,没有找到从StringKeyto的转换:String

error: value capitalize is not a member of this.Key[java.lang.String]

这很奇怪; 如果使用泛型类型参数声明,则存在从到 的转换Key[String]String

于 2011-01-31T17:43:33.800 回答
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]是允许将类型转换TKey[T]. 我还展示了base2key它的样子。

于 2011-01-28T20:25:13.587 回答