首先,如果你只是想縮短你的代碼,你可以做一些安全的選擇。同伴對象可以被視爲一個功能,所以你可以使用這樣的事情:
def build2[A,B,C](m: Map[A,B], f: (B,B) => C)(k1: A, k2: A): Option[C] = for {
v1 <- m.get(k1)
v2 <- m.get(k2)
} yield f(v1, v2)
build2(m, Image)("url", "title")
這將返回一個包含結果的選項。另外,您可以使用ApplicativeBuilder
S IN Scalaz在內部做幾乎相同,但有一個更好的語法:
import scalaz._, Scalaz._
(m.get("url") |@| m.get("title"))(Image)
如果你真的需要通過反射來這樣做,那麼最簡單的方法是使用Paranamer(如電梯 - 框架確實)。 Paranamer可以通過檢查字節碼來恢復參數名稱,所以性能會受到影響,並且由於類加載器問題(例如,REPL),它不適用於所有環境。如果你限制自己的類只有String
構造函數的參數,那麼你可以做這樣的:
val pn = new CachingParanamer(new BytecodeReadingParanamer)
def fill[T](m: Map[String,String])(implicit mf: ClassManifest[T]) = for {
ctor <- mf.erasure.getDeclaredConstructors.filter(m => m.getParameterTypes.forall(classOf[String]==)).headOption
parameters = pn.lookupParameterNames(ctor)
} yield ctor.newInstance(parameters.map(m): _*).asInstanceOf[T]
val img = fill[Image](m)
(注意這個例子可以選擇一個默認的構造函數,因爲它不會檢查你會想參數計數千萬)
build2的類型參數與字段數成正比。我不這麼整潔,我想。 – 2014-10-09 21:02:01