2016-08-10 1 views
1

У меня возникли проблемы с реорганизацией общего кода из 3-х методов и в makeRequest(), но я получаю неоднозначное неявное соответствие от компилятора. Я не уверен, что это из-за наличия умолчаний для неявных методов или какой-то другой проблемы, но моя цель заключается в том, что getRequest/deleteRequest/postRequest может просто вызвать makeRequest («GET»)/makeRequest («DELETE»)/makeRequest («POST»)). Ранее ни один из параметров не был неявными, я просто пытаюсь достичь цели, используя implicitsScala несколько неявных параметров со значениями по умолчанию, приводящими к неоднозначным значениям

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

Один яркий красный флаг означает, что вам требуется 'implicit' для' String' - вы должны как можно больше избегать определения имплицитов для обычных типов ... Тем не менее, чтобы отлаживать неоднозначные импликации, вам нужно посмотреть вызов сайтов вышеуказанных методов и найти все импликации в области видимости, поэтому информации, которую вы нам предоставили, недостаточно. – Alec

+0

@Alec, я разъясню это в сообщении после этого комментария, но ранее у getRequest/deleteRequest/postRequest были только явные параметры, я пытаюсь реорганизовать общий код из 3-х методов в makeRequest, чтобы я мог сделать каждый метод просто вызовом, т. Е. makeRequest ("GET").Для этого я пытаюсь использовать implicits – irregular

+3

Игнорирует поиск только по типу, а не по имени, поэтому использование 'String' не будет работать должным образом. – Reactormonk

ответ

7

Я думаю, вы должны повторно использовать все эти неявный если вы не делаете действительно фанки DSL.

Вот один из способов решения проблемы, с которой вы сталкиваетесь. Как вы, возможно, догадались, неявная работа над типом, а не с именем, поэтому наличие двух неявных с одним типом - это No-No.

С Scala 2.10 Scala позволяет вам «встроить» классы с помощью 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

Совет по упаковке типов был очень информативным! На данный момент я буду придерживаться не-неявных значений, потому что добавление классов case для каждого параметра кажется кодовым табличным кодом для меня. Это определенно дало мне больше информации о том, как работают implicits, хотя спасибо – irregular

1

Как говорит Marios, проблема заключается в том, что вы используете implicits для таких типов, как String и Int. Поскольку implicits работают над типом, а не по имени, компилятор не знает, куда помещать «неявную строку». Вот почему должны использоваться пользовательские типы. Одна вещь, которую я убрал из последней конференции ScalaDays, заключается в том, что вы должны создавать типы для всего, потому что компилятор может помочь вам убедиться, что программа правильная.

Однако, глядя на ваше решение, я не буду использовать implicits вообще. Лучше использовать один список аргументов и предоставлять значения по умолчанию для всех или большинства значений. Тогда «makeRequest» может по умолчанию использовать «Get /», и это поведение может быть изменено путем предоставления «path =»/search «» или «method =» POST ».

Также используйте какой-то тип области действия для метода http, так как вы уже знаете, какие действительные значения и какие из них вы хотите поддержать.

Смежные вопросы