Mendefinisikan fungsi dengan beberapa argumen implisit di Scala

94

Bagaimana saya bisa mendefinisikan fungsi dengan beberapa argumen implisit.

def myfun(arg:String)(implicit p1: String)(implicit p2:Int)={} // doesn't work
Ali Salehi
sumber
2
Dalam teks pertanyaan Anda menanyakan tentang suatu fungsi. Di cuplikan kode Anda, Anda memiliki metode. Apakah Anda bertanya tentang suatu fungsi atau metode?
Jörg W Mittag

Jawaban:

190

Mereka semua harus masuk dalam satu daftar parameter, dan daftar ini harus menjadi yang terakhir.

def myfun(arg:String)(implicit p1: String, p2:Int)={} 
missingfaktor
sumber
1
Jika itu kelas, sintaksnya adalah kelas MyClass () (implisit p1: String, implisit p2: Int) {}
skjagini
2

Sebenarnya ada cara untuk melakukan apa yang dibutuhkan OP. Sedikit berbelit-belit, tetapi berhasil.

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

Dalam Scala 3 (alias "Dotty", meskipun ini adalah nama kompiler) alih-alih mengembalikan objek MyFunPart2 tambahan , dimungkinkan untuk mengembalikan nilai fungsi dengan argumen implisit secara langsung. Ini karena Scala 3 mendukung "Fungsi Implisit" (yaitu "parameter implisit" sekarang adalah bagian dari jenis fungsi). Beberapa daftar parameter implisit menjadi sangat mudah untuk diterapkan sehingga mungkin bahasa akan mendukungnya secara langsung, meskipun saya tidak yakin.

Mario Rossi
sumber
1

Ada cara lain (IMO yang lebih sederhana dan lebih fleksibel) untuk mencapai efek serupa:

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

Menggunakan Tuple sebagai representasi dasar untuk parameter bukanlah ide yang baik karena konversi implisit dapat mengganggu penggunaan lain. Sebenarnya, konversi implisit ke tipe standar apa pun (termasuk yang pustaka) biasanya menimbulkan masalah dalam aplikasi non-sepele. Solusinya adalah membuat kelas kasus khusus untuk menampung parameter, bukan Tuple. Keuntungan penting adalah mereka bisa diberi nama yang jauh lebih bermakna daripada _1 dan _2.

Mario Rossi
sumber