2016-08-03 24 views
1

我有以下設置:如何使用模式匹配中的類型信息?

trait TypeA { override def toString() = "A" } 
trait TypeB { override def toString() = "B" } 
trait TypeC { override def toString() = "C" } 

def foo[T](t: T) = println(t) 

現在我可以做這樣的事情:

val valueB: Any = new TypeB {} 

val typedValue = valueB match { 
    case t: TypeA => foo(t) 
    case t: TypeB => foo(t) 
    case t: TypeC => foo(t) 
} 
// prints "B" 

如果我想概括這種模式匹配塊,我可以簡單地做:

val typedValue = valueB match { 
    case t => foo(t) 
} 

它會工作。但是,在我真正的用例中,我需要在調用方法時明確指定類型信息,因爲沒有函數參數可以從中推斷出來。所以如果foo()是一個泛型方法,參數化爲類型參數T,但沒有那個類型的實際參數來推斷,我可以將它推廣到只與一個case語句匹配的模式(可能使用Reflection API)?

那麼,如何推廣呢?

val typedValue = valueB match { 
    case t: TypeA => foo[TypeA]() 
    case t: TypeB => foo[TypeB]() 
    case t: TypeC => foo[TypeC]() 
    ... 
} 
+2

這似乎編譯:'情況下T => FOO [t.type]( )'試一試。 – jwvh

+0

困難的部分是,如何使模式匹配真正提取實際類型?我希望能夠說'val t:Any = ...',並且在模式匹配部分我會匹配實際的類型。看到編輯的問題(val valueB現在是'Any'類型)。如果'valueB'被聲明爲「Any」類型,那麼你的建議很不幸地不起作用,並且也有一個奇怪的消息(未指定的值參數:t.type)。 – slouc

回答

1

如果我想概括這種模式匹配塊,我可以簡單地做:

val typedValue = valueB match { 
    case t => foo(t) 
} 

一般來說,你不能。例如。如果foo(x: TypeA),foo(x: TypeB)foo(x: TypeC)是單獨的重載。這就是你的真實代碼的情況:你必須爲JsObject等編寫單獨的方法,因爲那些value調用恰好具有相同的名稱;你不能寫foo(x: JsValue)foo[T <: JsValue](x: T)這會做你想做的(沒有你想要避免的相同匹配)。

在你有一個多態方法的情況:因爲通用的參數將被刪除,如果你有def foo[T]() = ...foo[TypeA]()foo[TypeB]()foo[TypeC]()將執行相同的實際代碼(這並不適用於classOfisInstanceOfasInstanceOf ,但這些是唯一的例外,因爲它們不是真正的通用方法)。所以你可以撥打foo[<type-of-valueB>]。爲了使它們不同,foo必須具有取決於T的隱含參數,例如,

trait Baz[A] { ... } 
object Baz { 
    implicit val bazTypeA: Baz[TypeA] = ... 
    ... 
} 

def foo[A]()(implicit baz: Baz[A]) = ... 

在這種情況下,以避免分支的方式是該方法調用foo接受相同的隱式:

def bar[A](value: A)(implicit baz: Baz[A]) = foo[A]() 

bar(new TypeA) // uses bazTypeA 
+0

你能解釋這是如何工作的?這是使用Play JSON的片段;如果你不熟悉它,你會得到的重點。是不是JsNumber和JsString在運行時解決,因此應該被刪除? 'val result = json match {case jsString:JsString => json.as [JsNumber]。值} //不work' 和 'VAL結果= JSON匹配{殼體jsString:JsString => json.as [JsString]。價值} // works' 人們會期望兩個呼叫,'作爲[Jstring]'和'[JsNumber]'',就像你說的那樣觸發相同的代碼。但是類型參數有很大的不同。 – slouc

+1

'as'使用了一個隱含的參數,這個參數在我的答案最後被覆蓋。 –

+0

哦對。謝謝! – slouc