2011-01-28 46 views
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。或者在那里,也许使用隐式传递的类清单?考虑到这一点我找不到任何参考。

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

假设这个解决方案,是整个企业可行还是将规定的用例需要多重链式隐式转换,无论如何呢? (链接不会发生,因为我已阅读。)

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

+0

为什么使用Ordered而不是Ordering? – Landei 2011-01-28 14:37:00

+0

由于类型*是*排序的,但*具有*排序。它会有所作为吗?我如何实现一个产生排序的泛型/抽象函数? – Raphael 2011-01-28 14:44:31

+0

我想可能会传递顺序作为`foo`的隐式参数会起作用,但当然这与视图绑定冲突。 – Raphael 2011-01-28 14:54:44

回答

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) 

但实际上,从StringKeyString转换未发现:

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

这很奇怪;那么Key[String]String的转换,如果用泛型类型参数声明的话。

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的样子。

1

你问“是否有可能以某种方式静态声明任何类型的扩展Key[T]将带有隐式转换T => Key[T]?伴侣对象不能有抽象方法,不幸的是。

,但你的例子是一个静态断言:当你需要从TKey[T]视图,你断言在编译的时候,你可能只调用foo为此可以解除键的类型。或者我误解了什么?

关于附录:你说你很惊讶,“从KKey[K]的转换隐式发生,即使它从来没有被我声明过”。事情是,你是把它声明:T <% Key[T](我用T这里,而不是K,你似乎基地的概念* 牛逼 * YPE和* ķ *安永在这里被混淆?)。这是相同的

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

因此,当你做你sortWith(_ <= _)强迫TKey[T](对于该<=被定义为每性状Ordered[Key[T]])。

把你的节点例如,为什么不这样做

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

希望帮助...