Визначення функції з декількома неявними аргументами у Scala


94

Як я можу визначити функцію з кількома неявними аргументами.

def myfun(arg:String)(implicit p1: String)(implicit p2:Int)={} // doesn't work

2
У тексті запитання ви запитуєте про функцію. У фрагменті коду у вас є метод. Ви питаєте про функцію чи метод?
Йорг W Міттаг

Відповіді:


190

Усі вони повинні входити до одного списку параметрів, і цей список повинен бути останнім.

def myfun(arg:String)(implicit p1: String, p2:Int)={} 

1
Якби це клас, синтаксис був би класом MyClass () (неявна p1: String, неявна p2: Int) {}
skjagini

2

Насправді існує спосіб робити саме те, що вимагає ОП. Трохи перекручений, але це працює.

class MyFunPart2(arg: String, /*Not implicit!*/ p1: String) {
  def apply(implicit p2: Int) = {
    println(arg+p1+p2)
    /* otherwise your actual code */
  }
}

def myFun(arg: String)(implicit p1: String): MyFunPart2= {
  new MyFunPart2(arg, p1)
}

implicit val iString= " world! "
implicit val iInt= 2019

myFun("Hello").apply
myFun("Hello")(" my friend! ").apply
myFun("Hello")(" my friend! ")(2020)

//  Output is:
//      Hello world! 2019
//      Hello my friend! 2019
//      Hello my friend! 2020

У Scala 3 (він же "Dotty", хоча це ім'я компілятора) замість повернення допоміжного об'єкта MyFunPart2 можливо повернути значення функції з неявними аргументами безпосередньо. Це тому, що Scala 3 підтримує "Неявні функції" (тобто "неявність параметрів" зараз є частиною типів функцій). Кілька неявних списків параметрів стають настільки простими для реалізації, що можливо, мова буде підтримувати їх безпосередньо, хоча я не впевнений.


1

Існує ще один (більш простий і гнучкий) режим IMO для досягнення подібного ефекту:

// Note the implicit is now a Tuple2
def myFun(arg: String)(implicit p: (String, Int) ): Unit = {
  println(arg + p._1 + p._2)
  /*otherwise your actual code*/
}

// These implicit conversion are able to produce the basic implicit (String,Int) Tuples
implicit def idis(implicit is: String, ii: Int): (String,Int)= (is,ii)
implicit def idi(s: String)(implicit ii: Int): (String,Int)= (s,ii)

// The basic implicit values for both underlying parameters
implicit val iString = " world! "
implicit val iInt = 2019

myFun("Hello")
myFun("Hello")(" my friend! ")
myFun("Hello")(" my friend! ",2020)

// Output is:
//     Hello world! 2019
//     Hello my friend! 2019
//     Hello my friend! 2020

// If we add the following implicit, 
implicit def ids(i: Int)(implicit is: String)= (is,i)

// we can even do
myFun("Hello")(2020)

// , and output is:
//     Hello world! 2020

Використання Tuple як основного подання для параметрів не є гарною ідеєю, оскільки неявні перетворення можуть заважати іншим способам використання. Насправді неявні перетворення в будь-який стандартний тип (включаючи бібліотечні) зазвичай створюють проблеми в будь-якому нетривіальному додатку. Рішення полягає у створенні виділеного класу випадків, щоб утримувати параметри замість Tuple. Важливою перевагою є те, що їм можна було назвати набагато більш значущі імена, ніж _1 та _2.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.