Çıkarım Türleri
Scala'daki imalar, tabiri caizse, "otomatik olarak" geçirilebilen bir değeri veya bir türden diğerine otomatik olarak yapılan bir dönüşümü ifade eder.
Örtük Dönüşüm
Tek bir yöntemi çağırırsa, ikincisi türü hakkında çok kısaca konuşan m
bir nesne üzerinde o
bir sınıfın C
ve bu sınıf destek yöntemi yok değil m
, o zaman Scala gelen bir örtük dönüştürme arayacaktır C
şey yapar desteği m
. Basit bir örnek yöntem olacaktır map
ile String
:
"abc".map(_.toInt)
String
yöntemi desteklemiyor map
, ancak StringOps
yapar ve bir örtük dönüşüm gerçekleşmesi String
için StringOps
(bkz mevcut implicit def augmentString
üzerine Predef
).
Örtük Parametreler
Öteki örtük tür, örtük parametredir . Bunlar, diğer parametreler gibi yöntem çağrılarına geçirilir, ancak derleyici bunları otomatik olarak doldurmaya çalışır. Eğer yapamazsa şikayet edecektir. Bu parametreleri açık bir şekilde aktarabiliriz, örneğin bu nasıl kullanılır breakOut
(örneğin breakOut
, bir meydan okuma için hissettiğiniz bir gün hakkındaki soruya bakın ).
Bu durumda, foo
yöntem bildirimi gibi örtük bir gereksinim olduğu bildirilmelidir:
def foo[T](t: T)(implicit integral: Integral[T]) {println(integral)}
Sınırları Görüntüle
Örtük olanın hem örtük bir dönüşüm hem de örtük bir parametre olduğu bir durum vardır. Örneğin:
def getIndex[T, CC](seq: CC, value: T)(implicit conv: CC => Seq[T]) = seq.indexOf(value)
getIndex("abc", 'a')
getIndex
Sınıfından örtük bir dönüştürme olduğu sürece yöntem herhangi bir nesneyi alabilir Seq[T]
. Bu nedenle, bir ' String
e geçebilirim getIndex
ve işe yarayacaktır.
Perde arkasında derleyici değiştirir seq.IndexOf(value)
için conv(seq).indexOf(value)
.
Bu çok faydalıdır, bunları yazmak için sözdizimsel şeker vardır. Bu sözdizimsel şekeri kullanarak, getIndex
şu şekilde tanımlanabilir:
def getIndex[T, CC <% Seq[T]](seq: CC, value: T) = seq.indexOf(value)
Bu sözdizimsel şeker, bir üst sınıra ( ) veya bir alt sınıra ( ) benzer bir görünüm bağlı olarak tarif edilir .CC <: Seq[Int]
T >: Null
Bağlam Sınırları
Örtük parametrelerde bir diğer yaygın örüntü tip sınıfı örüntüsüdür . Bu örüntü, onları açıklamayan sınıflara ortak arayüzlerin sağlanmasını sağlar. Hem bir köprü modeli - hem de endişelerin ayrılmasını sağlamak - hem de bir adaptör deseni olarak hizmet edebilir.
Integral
Bahsettiğiniz sınıf tipi sınıfı modelinin klasik bir örneğidir. Scala'nın standart kütüphanesindeki diğer bir örnek Ordering
. Scalaz adı verilen bu kalıbı yoğun kullanan bir kütüphane var.
Bu kullanımının bir örneğidir:
def sum[T](list: List[T])(implicit integral: Integral[T]): T = {
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
Bir denir bunun için sözdizimsel şeker de bulunmaktadır bağlı bağlam örtülü başvurmak için ihtiyaç tarafından daha az yararlı yapılır. Bu yöntemin düz bir dönüşümü şöyle görünür:
def sum[T : Integral](list: List[T]): T = {
val integral = implicitly[Integral[T]]
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
Bağlam sınırları, yalnızca bunları kullanan diğer yöntemlere aktarmanız . Örneğin, yöntemin örtük sorted
olması Seq
gerekir Ordering
. Bir yöntem oluşturmak için aşağıdakiler reverseSort
yazılabilir:
def reverseSort[T : Ordering](seq: Seq[T]) = seq.sorted.reverse
Çünkü Ordering[T]
örtülü geçildi reverseSort
, o zaman için örtülü iletebiliriz sorted
.
Etkiler nereden geliyor?
Derleyici, nesnenin sınıfında bulunmayan bir yöntemi çağırdığınız veya örtük bir parametre gerektiren bir yöntemi çağırdığınız için örtük bir gereksinim gördüğünde, ihtiyaca uygun bir örtük arar .
Bu arama, hangi etkilerin görünür ve hangilerinin görünmediğini tanımlayan belirli kurallara uyar. Derleyicinin çıkarımları nerede arayacağını gösteren aşağıdaki tablo , Josh Suereth tarafından yazılan Scala bilgisini geliştirmek isteyen herkese yürekten tavsiye ettiğim mükemmel bir sunumdan alınmıştır . O zamandan beri geri bildirim ve güncellemelerle tamamlandı.
Aşağıdaki 1 numara altında mevcut olan çıkarımlar 2 numara altındakilere göre daha önceliklidir. Bunun dışında, örtük parametrenin türüyle eşleşen birkaç uygun argüman varsa, statik aşırı yüklenme çözünürlüğü kuralları kullanılarak en spesifik olanı seçilecektir (bakınız Scala) Şartname §6.26.3). Daha ayrıntılı bilgi, bu cevabın sonunda bağlantı verdiğim bir soruda bulunabilir.
- Mevcut kapsamda ilk bakış
- Mevcut kapsamda tanımlanan çıkarımlar
- Açık ithalat
- joker ithalat
Diğer dosyalarda aynı kapsam
- Şimdi ilişkili türlere bakın
- Bir türün tamamlayıcı nesneleri
- Bağımsız değişken türünün örtük kapsamı (2.9.1)
- Kapalı tür argümanlarının kapsamı (2.8.0)
- İç içe tipler için dış nesneler
- Diğer boyutlar
Onlara bazı örnekler verelim:
Mevcut Kapsamda Tanımlanan Çıkarımlar
implicit val n: Int = 5
def add(x: Int)(implicit y: Int) = x + y
add(5) // takes n from the current scope
Açık İthalatlar
import scala.collection.JavaConversions.mapAsScalaMap
def env = System.getenv() // Java map
val term = env("TERM") // implicit conversion from Java Map to Scala Map
Joker Karakter İçe Aktarma
def sum[T : Integral](list: List[T]): T = {
val integral = implicitly[Integral[T]]
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
Diğer Dosyalarda Aynı Kapsam
Edit : Bu farklı bir önceliği yok gibi görünüyor. Öncelik ayrımı gösteren bir örneğiniz varsa, lütfen yorum yapın. Aksi takdirde, buna güvenmeyin.
Bu ilk örnek gibidir, ancak örtülü tanımın kullanımından farklı bir dosyada olduğu varsayılarak. Nesnelerin nasıl paketlendiğine de bakın çıkarımlarda bulunmak için kullanılabileceğini .
Bir Türün Tamamlayıcı Nesneleri
Burada iki nesne arkadaşı var. İlk olarak, "kaynak" türünün nesne arkadaşı incelenir. Örneğin, nesnenin içinde Option
örtük bir dönüştürme vardır Iterable
, böylece bir kişi Iterable
yöntemleri arayabilir Option
veya Option
bir Iterable
. Örneğin:
for {
x <- List(1, 2, 3)
y <- Some('x')
} yield (x, y)
Bu ifade derleyici tarafından şu dile çevrilir:
List(1, 2, 3).flatMap(x => Some('x').map(y => (x, y)))
Ancak, List.flatMap
bir beklediğini TraversableOnce
, hangi Option
değildir. Derleyici daha sonra Option
nesnenin arkadaşına bakar ve bu ifadeyi, bu ifadeyi doğru yapan Iterable
a dönüşümü bulur TraversableOnce
.
İkinci olarak, beklenen türde tamamlayıcı nesne:
List(1, 2, 3).sorted
Yöntem sorted
, örtük bir yöntem alır Ordering
. Bu durumda, nesnenin içine bakar Ordering
, sınıfa eşlik eder Ordering
ve Ordering[Int]
orada bir örtük bulur .
Süper sınıfların eşlik eden nesnelerine de bakıldığını unutmayın. Örneğin:
class A(val n: Int)
object A {
implicit def str(a: A) = "A: %d" format a.n
}
class B(val x: Int, y: Int) extends A(y)
val b = new B(5, 2)
val s: String = b // s == "A: 2"
Bu Scala örtük nasıl bulduğunu olduğunu Numeric[Int]
ve Numeric[Long]
bunların içinde bulanan olarak, bu arada, sorunuzu Numeric
değil Integral
.
Bağımsız Değişken Türünün Kapalı Kapsamı
A
Bağımsız değişken türünde bir yönteminiz varsa , örtük tür kapsamı A
da dikkate alınacaktır. "Örtük kapsam" ile, tüm bu kuralların yinelemeli olarak uygulanacağını kastediyorum - örneğin, tamamlayıcı nesnesi A
yukarıdaki kurala göre çıkarımlar için aranacaktır.
Bunun, örtük kapsamının A
o parametrenin dönüşümlerinin değil, tüm ifadenin aranacağı anlamına geldiğini unutmayın . Örneğin:
class A(val n: Int) {
def +(other: A) = new A(n + other.n)
}
object A {
implicit def fromInt(n: Int) = new A(n)
}
// This becomes possible:
1 + new A(1)
// because it is converted into this:
A.fromInt(1) + new A(1)
Bu Scala 2.9.1'den beri mevcuttur.
Tür Bağımsız Değişkenlerinin Kapalı Kapsamı
Tür sınıfı modelinin gerçekten çalışması için bu gereklidir. Ordering
Örneğin, şunu düşünün : Tamamlayıcı nesnesinde bazı çıkarımlarla birlikte gelir, ancak buna bir şeyler ekleyemezsiniz. Peki Ordering
otomatik olarak bulunan kendi sınıfınız için nasıl bir yapabilirsiniz ?
Uygulama ile başlayalım:
class A(val n: Int)
object A {
implicit val ord = new Ordering[A] {
def compare(x: A, y: A) = implicitly[Ordering[Int]].compare(x.n, y.n)
}
}
Yani, aradığınızda ne olacağını düşünün
List(new A(5), new A(2)).sorted
Gördüğümüz gibi, yöntem bir sorted
bekler Ordering[A]
(aslında Ordering[B]
, nerede, bekler B >: A
). İçinde böyle bir şey Ordering
yok ve bakılacak bir "kaynak" türü yok. Açıkçası, içeride bu aralar A
bir olan tip argüman arasında Ordering
.
Bu aynı zamanda çeşitli toplama yöntemlerinin nasıl CanBuildFrom
çalışacağını da gösterir: etkileri, tamamlayıcı nesnelerin içinde tür parametrelerine bulunur CanBuildFrom
.
Not :, bir tür parametresi olduğu Ordering
şeklinde tanımlanır . Daha önce, Scala'nın çok anlamlı olmayan tip parametrelerine baktığını söyledim. Yukarıda aranan örtüktrait Ordering[T]
T
Ordering[A]
yerlerde, A
parametrenin yazın değil, gerçek bir türüdür: bir olan tip argüman için Ordering
. Scala teknik özellikleri bölüm 7.2'ye bakınız.
Bu Scala 2.8.0'dan beri mevcuttur.
Yuvalanmış Türler için Dış Nesneler
Aslında bunun örneklerini görmedim. Birisi paylaşabilirse minnettar olurum. İlke basit:
class A(val n: Int) {
class B(val m: Int) { require(m < n) }
}
object A {
implicit def bToString(b: A#B) = "B: %d" format b.m
}
val a = new A(5)
val b = new a.B(3)
val s: String = b // s == "B: 3"
Diğer Ölçüler
Eminim ki bu bir şakaydı ama bu cevap güncel olmayabilir. Bu soruyu, olup bitenlerin son hakemi olarak almayın ve eğer güncelliğini yitirdiğini fark ederseniz, lütfen düzeltebilmem için beni bilgilendirin.
DÜZENLE
İlgili ilgi alanları: