2016-08-10 4 views
1

3 가지 방법 중 공통 코드를 리팩토링하는 문제와 makeRequest()으로 실행하고 있지만 컴파일러에서 모호한 암시 적 일치를 얻습니다. 이것은 암시 적 메서드 또는 다른 문제에 대한 기본값을 갖는 것이지 확실하지 않지만 내 목표는 getRequest/deleteRequest/postRequest는 단순히 makeRequest ("GET")/makeRequest ("DELETE")/makeRequest ("POST"). 이전 매개 변수 중 어떤 것도 암시, 난 그냥 사용 implicits 기본값이 모호한 여러 암시 적 매개 변수가 스칼라 값이됩니다.

def makeRequest(method: String)(implicit path: String, base: String, params: Seq[(String, String)], body: Option[String], retriesLeft: Int): Future[WSResponse] = ??? 

def getRequest()(implicit path: String, base: String = baseUrl, params: Seq[(String, String)] = Seq(), body: Option[String] = None, retriesLeft: Int = retries): Future[WSResponse] = makeRequest("GET") 

def deleteRequest()(implicit path: String, base: String = baseUrl, params: Seq[(String, String)] = Seq(), body: Option[String] = None, retriesLeft: Int = retries): Future[WSResponse] = makeRequest("GET") 

def postRequest[T]()(path: String, body: T, base: String = baseUrl, params: Seq[(String, String)] = Seq(), retriesLeft: Int = retries) 
    (implicit wrt: play.api.http.Writeable[T], ct : play.api.http.ContentTypeOf[T]): Future[WSResponse] = makeRequest("POST") 

나는이 얻을

하여 목표에 도달하려고 시도하지 않고 같은거야 하였다는 deleteRequest

ambiguous implicit values: 
[error] both value base of type String 
[error] and value path of type String 
[error] match expected type String 
[error]  def getRequest()(implicit path: String, base: String = baseUrl, params: Seq[(String, String)] = Seq(), body: Option[String] = None, retriesLeft: Int = retries): Future[WSResponse] = makeRequest("GET") 
+1

눈부신 적색 플래그 중 하나는'String'에'암시 적 '이 필요하다는 것입니다 - 가능한 한 많이 일반적인 유형에 대한 암시를 정의하지 말아야합니다 ...하지만 모호한 implicits를 디버깅하려면 호출을 봐야합니다 범위의 모든 함축을 찾으십시오. 그래서 우리가 제공 한 정보가 충분하지 않습니다. – Alec

+0

@Alec, 나는이 주석 다음 게시물에서 이것을 명확히 할 것이다. 그러나 이전에 getRequest/deleteRequest/postRequest는 명시적인 매개 변수만을 가졌으므로 각 메소드를 간단하게 호출 할 수 있도록 makeRequest에있는 3 개의 메소드의 공통 코드를 리펙토링하려고 시도하고있다. makeRequest ("GET").이렇게하려면 implicits를 사용하려고 시도합니다. – irregular

+3

Implicits는 이름이 아닌 유형별로만 검색하므로'String '을 사용하면 예상대로 작동하지 않습니다. – Reactormonk

답변

7

와 나는이 모든 암시를 사용하여 다시 방문해야한다고 생각 당신이 정말로 펑키 한 DSL을하고 있지 않다면.

여기에있는 문제를 해결하는 한 가지 방법이 있습니다. 당신이 짐작 했겠지만, 타입이 아닌 이름에 암묵적으로 작용할 수 있습니다. 그래서 같은 타입을 암묵적으로 두 개 갖는 것은 No-No입니다.

스칼라 2.10부터 스칼라에서는 AnyVal (SIP-15)을 사용하여 클래스를 "인라인"할 수 있습니다.

case class Path(p: String) extends AnyVal 

이제 대신하여 개체를 나타내는 문자열을 사용하여이 좋은 "래퍼"클래스 묶 : 여기에 소위 값 클래스의 예입니다. 이것에 관한 멋진 점은 컴파일 타임에 컴파일러가 코드의 모든 Path 객체를 String으로 바꾸는 것을 처리한다는 것입니다. 따라서 컴파일 된 코드 측면에서 보면 String을 사용하는 것과 동일한 성능을 얻을 수 있습니다. 런타임 패널티를 지불하지 않고도 많은 유형의 안전성을 확보 할 수 있습니다.

자, 여기 당신이 가지고있는 문제를 해결하는 방법입니다 다시 케이스에 오는 :

case class Path(s: String) extends AnyVal 
case class BaseUrl(s: String) extends AnyVal 

def foo(implicit a: Path, b: BaseUrl) = a.s ++ b.s 

implicit val a: Path = Path("a") 
implicit val b: BaseUrl = BaseUrl("b") 
다음

를 사용하는 방법입니다 : 마리오가 말했듯이

scala> foo 
res0: String = ab 
+1

유형을 감싸는 팁은 매우 유익했습니다! 지금은 각 매개 변수에 대문자 클래스를 추가하는 것이 보일러 플레이트 코드처럼 보이기 때문에 암묵적인 값을 사용하지 않을 것입니다. 이것은 분명히 나에게 implicits가 작동하는 방법에 대해 더 많은 통찰력을 주었지만 감사합니다. – irregular

1

, 문제가 있다는 것입니다을 당신은 String과 Int 같은 타입을위한 implicits을 사용하고 있습니다. implicits는 이름에 대한 것이 아닌 유형에 따라 작동하므로 컴파일러는 '암시 적 String'을 어디에 둘 것인지 알 수 없습니다. 그런 이유로 사용자 지정 형식을 사용해야합니다. 마지막 ScalaDays 컨퍼런스에서 한 가지 분명한 사실은 컴파일러가 프로그램이 올바른지 확인하는 데 도움이 될 수 있기 때문에 모든 유형에 대해 유형을 만들어야한다는 것입니다.

그러나 솔루션을 살펴보면, 나는 전혀 암시를 사용하지 않을 것입니다. 단일 인수 목록을 사용하고 모든 값 또는 대부분의 값에 대한 기본값을 제공하는 것이 좋습니다. 그런 다음 'makeRequest'는 기본적으로 'Get /'을 수행 할 수 있으며이 동작은 'path = "/ search"'또는 'method = "POST"'예를 들어 제공함으로써 변경 될 수 있습니다.

또한 유효한 값과 지원하려는 값을 이미 알고 있으므로 http 메서드에 대해 범위가 지정된 유형을 사용하십시오.