2011-01-28 45 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) 

希望幫助...