Yanıtlar:
Bunun zaten sorulduğunu sanıyordum, ancak öyleyse, soru "ilgili" çubukta belirgin değil. İşte burada:
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 A
için örtük bir B
kullanı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 :B
A
Ordered
def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b
Bir dönüştürme için A
bir 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ğ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:A
B[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 Array
parametreli bir türüne başlatma bir gerektirir ClassManifest
tip 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ığı implicitly
tü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.
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ı ç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 Int
olmadığı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 f
bunu bilmeniz gerekmez.
Ayrıca Ordered
, kütüphaneden en yaygın kullanım işleyen String
ve Array
onlar 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ü String
bir olacağını WrappedString
ve 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ı, 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 Ordering
yerini 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, ClassManifest
somut 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ı: