Scala tanımlayıcısı “örtük olarak” nedir?


169

implicitlyScala örneklerinde kullanılan adlı bir işlev gördüm . Bu nedir ve nasıl kullanılır?

Burada örnek :

scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
     |                         implicit def stringImpl = new Foo[String] {
     |                             def apply(list : List[String]) = println("String")
     |                         }
     |                         implicit def intImpl = new Foo[Int] {
     |                             def apply(list : List[Int]) =  println("Int")
     |                         }
     |                     } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit

scala> foo(1)
<console>:8: error: type mismatch;
 found   : Int(1)
 required: List[?]
       foo(1)
           ^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
 Foo[Double]
       foo(List(1.0))
          ^

implicitly[Foo[A]].apply(x)Derleyici düşündüğünden beri yazmamız gerektiğini unutmayın, bu parametrelerle implicitly[Foo[A]](x)çağırdığımız anlamına gelir implicitly.

Ayrıca bkz. Nesneleri / türleri / vb. Scala REPL firmasından? ve Scala olası sonuçları nerede arar?

Yanıtlar:


206

İşte en basit yöntemi kullanmak için birkaç neden implicitly.

Örtülü Görünümleri anlamak / sorunlarını gidermek için

Bir Örtülü görüntüleme seçimin öneki (örneğin göz önüne aldığımızda tetiklenebilir, the.prefix.selection(args)bir üye içermiyor selectionuygulanabilir args(hatta dönüştürmek için çalışıyor sonra argsÖrtülü Görünümler ile). Bu durumda, örtük üyeleri için derleyici görünüyor, yerel olarak tanımlı geçerli veya çevreleyen kapsamlarda, devralınan veya içe aktarılan, bunların türünden tanımlı veya eşdeğer örtük yöntemlere the.prefixsahip bir türe işlevler selection.

scala> 1.min(2) // Int doesn't have min defined, where did that come from?                                   
res21: Int = 1

scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>

scala> res22(1) // 
res23: AnyRef{def min(i: Int): Int} = 1

scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt

Örtülü Görünümler, bir ifade Beklenen Tür'e uymadığında aşağıdaki gibi de tetiklenebilir:

scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1

Derleyici bu işlevi arar:

scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>

Bağlama Bağımlı Bir Tanıtıcı Parametreye Erişme

Örtük parametreler muhtemelen Scala'nın Örtük Görünümlerden daha önemli bir özelliğidir. Tip sınıfı modelini desteklerler. Standart kütüphane bunu birkaç yerde kullanır - bakın scala.Orderingve nasıl kullanıldığı SeqLike#sorted. Örtük Parametreler, Array bildirimlerini ve CanBuildFromörneklerini iletmek için de kullanılır .

Scala 2.8, Bağlam Sınırları adı verilen örtük parametreler için steno sözdizimine izin verir. Kısaca, Aörtük tür parametresi gerektiren bir tür parametresine sahip bir yöntem M[A]:

def foo[A](implicit ma: M[A])

şu şekilde yeniden yazılabilir:

def foo[A: M]

Ancak örtük parametreyi geçirmenin, ancak adlandırmamasının anlamı nedir? Yöntemi uygularken bu nasıl faydalı olabilir foo?

Genellikle, örtük parametrenin doğrudan belirtilmesine gerek yoktur, adı verilen başka bir yönteme örtük bir argüman olarak tünellenir. Gerekirse, Bağlama Yöntemi ile terse yöntemi imzasını koruyabilir implicitlyve değeri gerçekleştirmeye çağırabilirsiniz :

def foo[A: M] = {
   val ma = implicitly[M[A]]
}

Örtük parametrelerin bir alt kümesini açıkça geçirme

Sınıf sınıfına dayalı bir yaklaşım kullanarak bir kişiyi güzel bir şekilde bastıran bir yöntem çağırdığınızı varsayın:

trait Show[T] { def show(t: T): String }
object Show {
  implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
  implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }

  def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}

case class Person(name: String, age: Int)
object Person {
  implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
    def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
  }
}

val p = Person("bob", 25)
implicitly[Show[Person]].show(p)

Ya adın çıkış şeklini değiştirmek istersek ne olur? Açık bir şekilde arayabiliriz PersonShow, açıkça bir alternatif geçirebiliriz Show[String], ancak derleyicinin anahtarını geçmesini istiyoruz Show[Int].

Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)

2
scala> 1.dak (2) res0: Int = 1 Scala 2.10.3'te Bir hata alıyorum: scala> dolaylı olarak [Int => {def min (i: Int): Herhangi bir}] <konsol>: 8: hata: Int => AnyRef {def min (i: Int): Any} için hiçbir örtülü görünüm yok. dolaylı olarak [Int => {def min (i: Int): Any}]
jhegedus

Bu cevap en son sürüm için güncellenecektir.
emeth

1
örtük olarak [Int => AnyVal {def min (i: Int): Int}] çalışacaktır. Cevapta düzeltilmelidir.
Malkaviano

212

ImplicitlyScala 2.8'de kullanılabilir ve Predef'de şu şekilde tanımlanır :

def implicitly[T](implicit e: T): T = e

Genellikle, örtük bir tür değerinin olup olmadığını kontrol etmek Tiçin kullanılır ve bu durumda geri döndürür .

Retronym sunumundan basit bir örnek :

scala> implicit val a = "test" // define an implicit value of type String
a: java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
       val c = implicitly[Int]
                         ^

6
Yöntem tam olarak kontrol etmez; örtük bir değer yoksa ve derlenmişse, derleme hatasına neden oluyor gibi görünüyor. Bunu neden kullanmak istediğime dair biraz daha bağlam verebilir misiniz?
davetron5000

17
implicitly[Ordering[(Int, String)]].compare( (1, "b"), (1, "a") ), özellikle bir Bağlam Bağımlı tarafından sunulan örtük bir parametreyi almak için:def foo[A: Ordering](a1: A, a2: A) = implicitly[Ordering[A]].compare(a1, a2)
retronym

1
Retronym'in yukarıdaki video bağlantısında tartışmasını görmek için 13:50 noktasına atlayın.
chaotic3quilibrium

-2

Bir "size balık tutmayı öğretin " cevabı şu anda Scaladoc gecelerinde mevcut olan alfabetik üye endeksini kullanmaktır . #Paket / sınıf bölmesinin üstündeki harfler (ve alfabetik olmayan adlar için), bu harfle başlayan üye adlarının dizinine (tüm sınıflarda) bağlanır. IÖrneğin, seçerseniz , oradaki bağlantıdan ziyaret edebileceğiniz implicitlybir olay içeren girişi bulacaksınız Predef.


46
Tabii ki, bu iskanlar dolaylı olarak hiçbir şey söylemiyorlar, bu yüzden dokümantasyon sayılmaz. Birisi bu yöntemin sadece bu dokümanlardan ne yaptığını nasıl anlar? Scala belgelerini rutin olarak hayal kırıklığına uğrattım. Yöntemlerin dolaylı gibi davranışı bariz olmaktan çok uzaktır ve üzerlerindeki dokümantasyon var olmamaktan çok daha iyidir. Stack Overflow için çok şükür. / bitiş sıralaması
Jeff


4
Tip imzası bunu oldukça iyi belgelemektedir.
Retronym

21
implicitScala'da önemli bir dil özelliği olarak görülüyor ve kesinlikle açıklamaya değer. Dokümanların sadece bir tür imza sayımını detaylandırdığını düşünmek, gerçek bir cevaptan ziyade entelektüel öz doyuma benziyor. OP tarafından sorulan belirli sorulara bakın - nedir ve nasıl kullanılır? Ne bu, ne de gerçek bir bağlantı bile sağlamadığınız gece belgelerinde cevaplandı. scala-lang.org/files/archive/nightly/docs/library/… Bu hiçbir şey öğretmez. Orijinal doküman örnekleri için Niklaus Wirth veya Turbo Pascal'a bakınız. -1
Thomas W

3
implicitve implicitlyilgili, ancak oldukça farklı. implicitAnahtar kelime dilinin bir parçasıdır. implicitlystandart kütüphanede düz Scala kodunda tanımlanır. Çevrimiçi dokümanlar kaynak bağlantıları içerdiğinden, sorgulayanları bu dokümanlara ve bağlantılı kaynağa yönlendirmenin en iyisi olduğuna inanıyorum.
Randall Schulz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.