Определение функции с несколькими неявными аргументами в Scala

95

Как я могу определить функцию с несколькими неявными аргументами.

def myfun(arg:String)(implicit p1: String)(implicit p2:Int)={} // doesn't work
Али Салехи
источник
3
В тексте вопроса вы спрашиваете о функции. Во фрагменте кода у вас есть метод. Вы спрашиваете о функции или методе?
Jörg W Mittag

Ответы:

190

Все они должны входить в один список параметров, и этот список должен быть последним.

def myfun(arg:String)(implicit p1: String, p2:Int)={} 
пропавший
источник
1
Если бы это был класс, синтаксис был бы class MyClass () (неявный p1: String, неявный p2: Int) {}
skjagini
2

На самом деле есть способ сделать именно то, что требует OP. Немного запутано, но работает.

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

Существует еще один (более простой и гибкий) способ добиться аналогичного эффекта:

// 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

Использование кортежа в качестве базового представления для параметров не является хорошей идеей, поскольку неявные преобразования могут мешать другим применениям. Собственно, неявные преобразования в любой стандартный тип (в том числе библиотечные) обычно создают проблемы в любом нетривиальном приложении. Решение состоит в том, чтобы создать специальный класс case для хранения параметров вместо Tuple. Важным преимуществом является то, что им можно было бы дать имена более значимые, чем _1 и _2.

Марио Росси
источник