Как да решим делегирането на метод със scala implicits

Как мога да разреша този прост проблем. Преобразуването на класа има въведен метод from, който взема два параметъра тип A и B и връща B от A. Дефинирах някои имплицитни елементи в придружаващия обект, за да осигуря поведение по подразбиране.

Моят проблем е, когато се опитам да препратя повикването към класа за преобразуване в друг въведен метод, който има същия подпис, той не работи. Тук в моя пример се опитвам да препратя извикването от функцията myFun към моя клас Conversion.

Получих следната грешка

  • няма достатъчно аргументи за метод от: (имплицитно f: A => B)

Чудя се защо това създава проблеми. Може ли някой да ми обясни защо и как да преодолея този проблем?

Ето кода

  object MyConversions {

     implicit val IntToStr = (f:Int) => f.toString()

     implicit val DoubleToStr = (f:Double) => f.toString()

     implicit val BooleanToStr = (f:Boolean) => f.toString()

  }

  class Conversions{
     def from[A,B](a:A)(implicit f:(A) => B) = {
       f(a)
     }
  }

  import MyConversions._;

  def myFun[A,B](a:A){
    // Error
    new Conversions().from[A, B](a)
  }

  // Working
  println( new Conversions().from[Int, String](3) )

person Jay    schedule 21.09.2015    source източник
comment
Няма имплицитно дефинирано общо f:(A) =› B в контекста.   -  person Ashalynd    schedule 21.09.2015
comment
Знам, но как мога да накарам това да работи по правилния начин. Мисля, че това е често срещан проблем.   -  person Jay    schedule 21.09.2015


Отговори (1)


Проблемът е, че компилаторът на Scala не може да намери неявна стойност за параметъра f: (A) => B в обхвата на myFun. Това, което трябва да направите, е да кажете на компилатора, че myFun може да се извика само когато има налична такава стойност.

Следният код трябва да свърши работа

object App {
  trait Convertible[A, B] {
    def convert(a: A): B
  }

  object Convertible {
    implicit val int2String = new Convertible[Int, String] {
      override def convert(a: Int): String = a.toString
    }

    implicit val float2String = new Convertible[Float, String] {
      override def convert(a: Float): String = a.toString
    }
  }

  def myFun[A ,B](a:A)(implicit converter: Convertible[A, B]): B = {
    converter.convert(a)
  }

  def main(args: Array[String]): Unit = {
    println(myFun(3))
  }
}
person Till Rohrmann    schedule 21.09.2015
comment
Мислех, че имплицитните ще бъдат търсени в типа на източника, който в този случай би бил Преобразувания. - person Jay; 21.09.2015
comment
Не, във вашия случай неявните ще бъдат търсени само в текущия обхват и придружаващите обекти на A и B. - person Till Rohrmann; 21.09.2015
comment
Един въпрос все още не ми е ясен. Как мога да направя обект Convertible разширим за други потребители, които могат да предоставят свои собствени косвени елементи, без да предават конкретен Convertible обект на myFun. Да кажем, че искаме друг метод, който преобразува Boolean в String? - person Jay; 21.09.2015
comment
За стандартните типове, като от Boolean до String, ще трябва да го добавите към придружаващия обект Convertible. Ако потребител дефинира нов тип, да кажем Foo, и иска да дефинира преобразуване от Foo към String, тогава той може да дефинира имплицитния Convertible[Foo, String] в придружаващия обект на Foo и той ще бъде намерен. - person Till Rohrmann; 21.09.2015
comment
Мога ли да ви задам друг въпрос? - person Jay; 21.09.2015
comment
Сигурен. Можете също така винаги да публикувате нов SO въпрос. - person Till Rohrmann; 21.09.2015
comment
Направих тази цигулка Пример. Все още има проблем, когато се използва с наследяване и скриване на информация. Направих проста клиентска извадка, която има различни възможности за транспорт. Искам потребителят да се обади на клиента, без да се притеснява за основния транспорт и реализациите. - person Jay; 21.09.2015
comment
Това няма да работи, защото не казвате на компилатора къде да намери Convertible[RawResult, T]. - person Till Rohrmann; 21.09.2015
comment
Знам, защото искам обаждащият се да може да каже, че искам списък [низ] обратно. В този случай List[String] е T. След това основният транспорт трябва да провери дали има преобразуване Convertible[RawResult, List[String] и да върне списъка. - person Jay; 21.09.2015
comment
Компилаторът може да попълни неявните стойности само ако знае конкретните типове. В случаите, когато типът не е известен, трябва да добавите контекстно обвързан или имплицитен параметър, който ще съдържа липсващата стойност. Всеки път, когато някой извика метода, той също трябва да се увери, че предоставя имплицитните стойности. Така става. - person Till Rohrmann; 21.09.2015