我正在爲簡單的休息請求使用Scala類型安全的構建器模式。這可以作爲流暢的API。隱式轉換不適用於類型安全的構建器模式
sealed abstract class Method(name: String)
case object GET extends Method("GET")
case object POST extends Method("POST")
abstract class TRUE
abstract class FALSE
case class Builder[HasMethod, HasUri](
method: Option[Method],
uri: Option[String]) {
def withMethod(method: Method): Builder[TRUE, HasUri] = copy(method = Some(method))
def withUri(uri: String): Builder[HasMethod, TRUE] = copy(uri = Some(uri))
}
implicit val init: Builder[FALSE, FALSE] = Builder[FALSE, FALSE](None, None)
//Fluent examples
val b1: Builder[TRUE, FALSE] = init.withMethod(GET)
val b2: Builder[TRUE, TRUE] = init.withMethod(GET).withUri("bar")
我想通過允許Method
實例轉換成Builder
實例,以使這更DSL的喜歡,但是當我加試隱含地包括init
建設者的隱式轉換和類型參數的組合混淆編譯器。
implicit def toMethod[HasUri](m: Method)
(implicit builder: Builder[_, HasUri]): Builder[TRUE, HasUri] = builder.withMethod(m)
// ** ERROR **: could not find implicit value for parameter builder:
// Builder[_, HasUri]
val b3: Builder[TRUE, TRUE] = GET withUri "foo"
// However the implicit parameter is discovered fine when function is called directly
val b4: Builder[TRUE, FALSE] = toMethod(GET)
val b5: Builder[TRUE, TRUE] = toMethod(GET) withUri "foo"
除b3以外的所有行編譯。當明確調用toMethod
函數時,可以隱式找到構建器參數。此外,如果我刪除通用參數(和類型安全)代碼按預期工作。
這是scala隱式轉換的限制嗎?或者我錯過了正確的語法來實現這一目標?
我想隱式發現初始構建器實例,以使用戶能夠爲其某些構建器的字段提供其默認值的初始構建器。
更新
我留下了一些代碼,以保持例子簡單,因爲它只是我正在修隱式轉換。
類型安全的建設者模式概括得非常好位置:http://blog.rafaelferreira.net/2008/07/type-safe-builder-pattern-in-scala.html
之後你只能調用build
方法一旦Builder
有一個方法和URI。
我想將構建器作爲隱式參數發現的原因是在DSL中支持以下情況。
url("http://api.service.org/person") apply { implicit b =>
GET assert(Ok and ValidJson)
GET/"john.doe" assert(NotFound)
POST body johnDoeData assert(Ok)
GET/"john.doe" assert(Ok and bodyIs(johnDoeData))
}
在這些情況下
- 新的構建是通過
url
- 這具有指定URI創建,然後在側重用封口
implicit b =>
- 的
assert
方法只適用,因爲已經指定了uri和方法 /
附加到當前uri,這是隻有建造者有指定的uri纔可用。
已指定方法和URI的另一個例子
GET url("http://api.service.org/secure/person") apply { implicit b =>
auth basic("harry", "password") assert(Ok and ValidJson)
auth basic("sally", "password") assert(PermissionDenied)
}
你可能想給這個看看,看看它是怎麼回事與具有隱含的PARAM你的隱函數揭示光。 http://stackoverflow.com/questions/5080406/implicit-parameters-in-implicit-conversions – cmbaxter 2013-05-12 22:30:59
我會重新考慮設計。您以一種奇怪的方式複製信息 - 一方面,您有一個類型構造函數參數,指示構建器在編譯時是否有方法或url,同時您擁有隻能在運行時解決的選項。問題是,你想達到什麼樣的目標(應該在哪裏檢查類型)?如果您使用類型參數,則創建攜帶該方法和url的子類(而不是選項)。最後,你想提升一個方法建設者。沒有必要檢查現有的'HasUri'類型,它應該總是'FALSE'? – 2013-05-12 22:50:36
@cmbaxter,謝謝,我會嘗試編譯我的代碼與這些調試選項,看看它是否擺脫任何光。 – iain 2013-05-13 08:57:44