Scala bağlamı ve görünüm sınırları nelerdir?


267

Basit bir şekilde, bağlam ve görünüm sınırları nelerdir ve aralarındaki fark nedir?

Bazı izlemesi kolay örnekler de harika olurdu!

Yanıtlar:


477

Bunun zaten sorulduğunu sanıyordum, ancak öyleyse, soru "ilgili" çubukta belirgin değil. İşte burada:

Görüntüleme Sınırı nedir?

Bir bağlanmış görünüşüdür bir tür kullanılmasını sağlamak için Scala kişiye bir mekanizma olduğu A gibi bu bir tür edildi B. Tipik sözdizimi şudur:

def f[A <% B](a: A) = a.bMethod

Diğer bir deyişle, türün bir nesne üzerindeki yöntemleri çağırabilmesi Aiçin örtük bir Bkullanılabilirliğe sahip olması gerekir . Standart kütüphanede (Scala 2.8.0'dan önce) en yaygın görüntüleme sınırlarının kullanımı şöyledir :BAOrdered

def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b

Bir dönüştürme için Abir içine Ordered[A], çünkü Ordered[A]yöntemi tanımlar <(other: A): Boolean, bir ifade kullanabilirsiniz a < b.

Görüntüleme sınırlarının kaldırıldığını lütfen unutmayın; bunlardan kaçınmalısınız.

Bağlama Bağlı Nedir?

Bağlam sınırları Scala 2.8.0'da tanıtıldı ve tipik olarak Haskell tipi sınıflar tarafından sağlanan işlevselliği taklit eden bir kod modeli olan tip sınıfı desen ile daha ayrıntılı bir şekilde kullanılır.

Bir görünüm sınırı basit türlerle (örneğin, A <% String) kullanılabilse de, bir bağlam sınırı , yukarıdaki gibi parametreli bir tür gerektirir Ordered[A], ancak bunun aksine String.

Bağlam bağlamı , görünüm sınırının örtük dönüşümü yerine örtük bir değeri tanımlar . Bazı türler için örtük bir tür değerinin bulunduğunu bildirmek için kullanılır. Sözdizimi şu şekilde gider:AB[A]

def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]

Bu, görünümden daha kafa karıştırıcıdır, çünkü nasıl kullanılacağı hemen net değildir. Scala'da yaygın kullanım örneği şudur:

def f[A : ClassManifest](n: Int) = new Array[A](n)

Bir Arrayparametreli bir türüne başlatma bir gerektirir ClassManifesttip silme ve dizilerin olmayan silme doğasına ilişkin gizli nedenlerle mevcut olması.

Kütüphanedeki diğer bir yaygın örnek biraz daha karmaşıktır:

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

Burada, sınıfın yöntemi tanımladığı implicitlytürden biri olan istediğimiz örtük değeri elde etmek Ordering[A]için kullanılır compare(a: A, b: A): Int.

Bunu aşağıda yapmanın başka bir yolunu göreceğiz.

Görüntüleme Sınırları ve Bağlam Sınırları nasıl uygulanır?

Tanımları göz önüne alındığında, hem görüntüleme sınırlarının hem de bağlam sınırlarının örtülü parametrelerle uygulanması şaşırtıcı olmamalıdır. Aslında, gösterdiğim sözdizimi, gerçekte olan şey için sözdizimsel şekerlerdir. Şekerini nasıl düşürdüklerine bakın:

def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod

def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)

Yani, doğal olarak, onları tam sözdiziminde yazabilir, bu da bağlam sınırları için özellikle yararlıdır:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)

Görüntüleme Sınırları ne için kullanılır?

Görüntüleme sınırları çoğunlukla , orijinal türü bir şekilde döndürmek istediğiniz durumlarda, varolan bir sınıfa "yöntemler" ekleyen pezevenk şablonumdan yararlanmak için kullanılır . Bu türü herhangi bir şekilde döndürmeniz gerekmiyorsa, bağlı bir görünüme ihtiyacınız yoktur.

Görünüme bağlı kullanımın klasik örneği işlemdir Ordered. Örneğin, örtük bir dönüşüm olmasına rağmen bunun Intolmadığını unutmayın Ordered. Daha önce verilen örnek, dönüştürülmemiş türü döndürdüğü için bir görünüme bağlı olmalıdır:

def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b

Bu örnek, görüntüleme sınırları olmadan çalışmaz. Ancak, başka bir tür dönmek için olsaydı, o zaman artık bağlı bir görünüm gerekmez:

def f[A](a: Ordered[A], b: A): Boolean = a < b

Buradaki dönüşüm (gerekirse) parametreyi geçmeden önce gerçekleşir f, bu yüzden fbunu bilmeniz gerekmez.

Ayrıca Ordered, kütüphaneden en yaygın kullanım işleyen Stringve Arrayonlar Scala koleksiyonları biri gibi Java sınıfları olan,. Örneğin:

def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b

Bir görünüm sınırları olmadan bunu yapmak için çalışması halinde, bir dönüş türü Stringbir olacağını WrappedStringve benzer için (Scala 2.8) Array.

Tür yalnızca dönüş türünün tür parametresi olarak kullanılsa bile aynı şey olur:

def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted

Bağlam Sınırları ne için kullanılır?

Bağlam sınırları, Haskell'in tip sınıflarına referans olarak, tipik olarak tip sınıfı desen olarak bilinen şeylerde kullanılır . Temel olarak, bu örüntü, bir tür örtülü adaptör örüntüsü yoluyla işlevselliği kullanılabilir hale getirerek mirasa bir alternatif uygular.

Klasik örnek, Scala'nın kütüphanesinin Orderingyerini alan Scala 2.8'lerdir Ordered. Kullanımı:

def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b

Yine de bunu böyle yazdığınızı göreceksiniz:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
    import ord.mkOrderingOps
    if (a < b) a else b
}

Bu Ordering, geleneksel operatör stilini etkinleştiren bazı örtük dönüşümlerden yararlanır . Scala 2.8'deki diğer bir örnek Numeric:

def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)

Daha karmaşık bir örnek, yeni koleksiyon kullanımıdır CanBuildFrom, ancak bununla ilgili çok uzun bir cevap var, bu yüzden burada önleyeceğim. Ve daha önce de belirtildiği gibi, ClassManifestsomut tipler olmadan yeni dizileri başlatmak için gerekli olan kullanım vardır.

Tip sınıf desenine bağlı bağlamın, endişelerin ayrılmasını sağladıkları için kendi sınıflarınız tarafından kullanılması çok daha olasıdır, oysa iyi tasarım ile kendi kodunuzda görünüm sınırlarından kaçınılabilir (çoğunlukla bir başkasının tasarımını dolaşmak için kullanılır) ).

Uzun zamandır mümkün olmasına rağmen, 2010 yılında bağlam sınırlarının kullanımı gerçekten başladı ve şimdi Scala'nın en önemli kütüphaneleri ve çerçevelerinde bir dereceye kadar bulundu. Bununla birlikte, kullanımının en uç örneği Haskell'in gücünü Scala'ya getiren Scalaz kütüphanesidir. Kullanılabileceği tüm yolları daha iyi tanımak için typeclass kalıplarını okumanızı tavsiye ederim.

DÜZENLE

İlgili ilgi alanları:


9
Çok teşekkür ederim. Bunun daha önce yanıtlandığını biliyorum, ve belki o zaman yeterince okumadım, ama buradaki açıklamanız gördüğüm en net. Tekrar teşekkür ederim.
chrsan

3
@chrsan İki bölüm daha ekledim, her birinin nerede kullanıldığı konusunda daha ayrıntılı bilgi edindim.
Daniel C.Sobral

2
Bunun mükemmel bir açıklama olduğunu düşünüyorum. Sizin için uygunsa bunu Almanca blogum (dgronau.wordpress.com) için çevirmek istiyorum.
Aralık'ta Landei

3
Bu, şimdiye kadar bulduğum bu konunun en iyi ve en kapsamlı açıklaması. Gerçekten çok teşekkür ederim!
fotNelton

2
Sooo, Scala kitabınız ne zaman çıkıyor ve nereden satın alabilirim :)
wfbarksdale
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.