2016-09-23 67 views
0

使用上下文範圍在Scala中,你可以做的東西一樣斯卡拉方面界定

trait HasBuild[T] { 
    def build(buildable: T): Something 
} 

object Builders { 
    implict object IntBuilder extends HasBuild[Int] { 
    override def build(i: Int) = ??? // Construct a Something however appropriate 
    } 
} 

import Builders._ 
def foo[T: HasBuild](input: T): Something = implicitly[HasBuild[T]].build(1) 
val somethingFormInt = foo(1) 

或者乾脆

val somethingFromInt = implicitly[HasBuild[Int]].build(1) 

我怎麼能表達有一個適當的隱含HasBuild任何元素的Seq的類型範圍內的對象?這可能沒有太多的魔法和外部庫?

Seq[WhatTypeGoesHere] - 我應該能夠找到每個元素

適當HasBuild這顯然不會編譯:

val buildables: Seq[_: HasBuild] = ??? 
+1

您的例子沒有在任何地方使用綁定上下文:當你只有HasHasBuild您可以使用隱式HasBuild參數的方法。它使用implicits。 –

+0

你是對的,更新。如果你知道我想要做的事情的名字,也可以隨時更新標題。 –

+0

你的意思是存在型嗎?像'val buildables:Seq [HasBuild [_]] = Seq(IntBuilder,SomeStringBuilder)' –

回答

1

基本上我希望能夠在一個共同的處理類型無關(例如:build),而用戶不需要手動將它們包裝在某種適配器中,並且由編譯器執行,實際上可以處理這些類型。不確定目的是否清楚。

有些事情,你可以這樣做:

case class HasHasBuild[A](value: A)(implicit val ev: HasBuild[A]) 
object HasHasBuild { 
    implicit def removeEvidence[A](x: HasHasBuild[A]): A = x.value 
    implicit def addEvidence[A: HasBuild](x: A): HasHasBuild[A] = HasHasBuild(x) 
} 

現在(假設你添加HasBuild[String]示範):

val buildables: Seq[HasHasBuild[_]] = Seq(1, "a") 

編譯,但

val buildables1: Seq[HasHasBuild[_]] = Seq(1, "a", 1.0) 

不。

def foo1[A](x: HasHasBuild[A]) = { 
    import x.ev // now you have an implicit HasBuild[A] in scope 
    foo(x.value) 
} 

val somethings: Seq[Something] = buildables.map(foo1(_)) 
+0

謝謝,這看起來不錯。 –

+0

它實際上是不完整的。我已經擴展它來顯示如何調用諸如'foo'的方法。 –

0

首先第一件事情,相反,一些評論,你是依靠在上下文邊界上。爲T請求一個隱式類型實例就是你所說的「上下文綁定」。

你想要什麼是可以實現的,但不是微不足道的,當然不是沒有其他庫。

import shapeless.ops.hlist.ToList 
import shapeless._ 
import shapeless.poly_ 

object builder extends Poly1 { 
    implicit def caseGeneric[T : HasBuilder] = { 
    at[T](obj => implicitly[HasBuilder[T]].build(obj)) 
    } 
} 

class Builder[L <: HList](mappings: L) { 
    def build[HL <: HList]()(
    implicit fn: Mapper.Aux[builder.type, L, HL], 
    lister: ToList[Something] 
) = lister(mappings map fn) 

    def and[T : HasBuilder](el: T) = new Builder[T :: L](el :: mappings) 
} 


object Builder { 
    def apply[T : HasBuilder](el: T) = new Builder(el :: HNil) 
} 

現在你也許能夠做的東西,如:

Builder(5).and("string").build() 

這會召喚出所有的個體implcit類型的類實例的build方法,給你的結果,其中每個列表結果有類型Something。它依賴於一個事實,即所有的構建方法具有較低上限的Something,例如:根據你的例子:

trait HasBuild[T] { 
    def build(buildable: T): Something 
} 
+0

謝謝,但我想自由地執行依賴關係。解決方案@Alexey建議將所有內容都包裝在案例類中,但它會通過暗示自動發生,所以對我來說沒問題。 –

+0

@ bali182我同意,它更乾淨;我不知道你可以這樣做 – flavian