Scala 2.8'in yeni özelliklerinden biri bağlam sınırlarıdır. Bağlama bağlı nedir ve nerede yararlıdır?
Elbette önce araştırdım (ve örneğin bunu buldum ) ancak gerçekten net ve ayrıntılı bir bilgi bulamadım.
Scala 2.8'in yeni özelliklerinden biri bağlam sınırlarıdır. Bağlama bağlı nedir ve nerede yararlıdır?
Elbette önce araştırdım (ve örneğin bunu buldum ) ancak gerçekten net ve ayrıntılı bir bilgi bulamadım.
Yanıtlar:
Eğer buldunuz bu yazıyı ? Dizi iyileştirmeleri bağlamında yeni bağlama bağlı unsuru kapsar.
Genel olarak, bağlam bağlantılı bir tür parametresi biçimdedir [T: Bound]
; türden T
örtük bir parametre ile birlikte düz tür parametresine genişletilir Bound[T]
.
tabulate
Belirli bir f fonksiyonunun 0'dan belirli bir uzunluğa kadar olan bir sayı aralığına uygulanmasının sonuçlarından bir dizi oluşturan yöntemi düşünün . Scala 2.7'ye kadar, tablo aşağıdaki gibi yazılabilir:
def tabulate[T](len: Int, f: Int => T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
Scala 2.8'de bu artık mümkün değildir, çünkü doğru temsili oluşturmak için çalıştırma zamanı bilgisi gereklidir Array[T]
. Bu bilgiyi ClassManifest[T]
yönteme örtük bir parametre olarak iletmek gerekir :
def tabulate[T](len: Int, f: Int => T)(implicit m: ClassManifest[T]) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
Bir kısaltma biçimi olarak, bunun yerine tür parametresinde bir bağlam sınırı kullanılabilir T
, bu da:
def tabulate[T: ClassManifest](len: Int, f: Int => T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
Robert'ın cevabı, Bağlam Sınırlarının teknik ayrıntılarını kapsıyor. Size onların anlamları hakkında yorumumu vereceğim.
Scala'da View Bound ( A <% B
), 'olarak görülebilir' <:
kavramını yakalar (oysa bir üst sınır , 'a'dır' kavramını yakalar). Bir bağlam sınırı ( A : C
), bir tür hakkında 'vardır' der. Manifestlerle ilgili örnekleri " T
has a Manifest
" olarak okuyabilirsiniz . Ordered
About vs bağlantısına bağladığınız Ordering
örnek, farkı göstermektedir. Bir metod
def example[T <% Ordered[T]](param: T)
parametrenin bir Ordered
. İle karşılaştırmak
def example[T : Ordering](param: T)
parametrenin bir ilişkili olduğunu söyleyen Ordering
.
Kullanım açısından, sözleşmelerin oluşturulması biraz zaman aldı, ancak bağlam sınırları, görünüm sınırları yerine tercih ediliyor ( görünüm sınırları artık kullanımdan kaldırılmıştır ). Bir öneri, örtük bir tanımı bir kapsamdan diğerine doğrudan başvurmaya gerek kalmadan aktarmanız gerektiğinde bağlam sınırının tercih edilmesidir (bu kesinlikle ClassManifest
bir dizi oluşturmak için kullanılan durumdur ).
Görünüm sınırları ve bağlam sınırları hakkında düşünmenin başka bir yolu, ilkinin, arayanın kapsamından örtük dönüşümleri aktarmasıdır. İkincisi, örtük nesneleri arayanın kapsamından aktarır.
has a
Bana daha mantıklı geliyor]
(Bu, parantez içinde bir nottur. Önce diğer cevapları okuyup anlayın.)
Bağlam Sınırları aslında Görünüm Sınırlarını genelleştirir.
Dolayısıyla, Görünüm Sınırı ile ifade edilen bu kod verildiğinde:
scala> implicit def int2str(i: Int): String = i.toString
int2str: (i: Int)String
scala> def f1[T <% String](t: T) = 0
f1: [T](t: T)(implicit evidence$1: (T) => String)Int
Bu, aynı zamanda tip fonksiyonları temsil eden bir tür diğer adı yardımıyla, Bound Bağlamında ile ifade edilebilir F
türüne T
.
scala> trait To[T] { type From[F] = F => T }
defined trait To
scala> def f2[T : To[String]#From](t: T) = 0
f2: [T](t: T)(implicit evidence$1: (T) => java.lang.String)Int
scala> f2(1)
res1: Int = 0
Bir tür oluşturucu ile bağlam sınırı kullanılmalıdır * => *
. Bununla birlikte, tür kurucusu Function1
bir türdür (*, *) => *
. Tür diğer adının kullanımı, türle ikinci tür parametreyi kısmen uygularString
, türle ve bağlam bağlı olarak kullanım için doğru türden bir tür yapıcısı verir.
Bir özellik içinde tür takma adını kullanmadan, kısmen uygulanan türleri Scala'da doğrudan ifade etmenize izin veren bir öneri vardır. Daha sonra yazabilirsiniz:
def f3[T : [X](X => String)](t: T) = 0
From
Çeşidi To[String]
. Bir tür bağımsız değişkeni sağlamıyoruz From
, bu nedenle bir türe değil, tür oluşturucuya atıfta bulunuyoruz. Bu tür kurucu, bağlam sınırı olarak kullanılacak doğru türdendir - * -> *
. Bu, türden T
örtük bir parametre gerektirerek tür parametresini sınırlar To[String]#From[T]
. Tür takma adlarını genişletin ve işte size kaldı Function1[String, T]
.
Bu başka bir parantez notudur.
Ben'in işaret ettiği gibi , bağlama bağlı bir tür parametresi ile bir tür sınıfı arasındaki "has-a" kısıtlamasını temsil eder. Başka bir deyişle, belirli bir tür sınıfın örtük bir değerinin var olduğuna dair bir kısıtlamayı temsil eder.
Bağlam sınırını kullanırken, çoğu zaman bu örtük değeri yüzeye çıkarmak gerekir. Örneğin, kısıtlama verildiğinde, T : Ordering
çoğu zaman Ordering[T]
kısıtlamayı karşılayan örneğine ihtiyaç duyulur . Burada gösterildiği gibi , implicitly
yöntemi veya biraz daha yararlı bir context
yöntemi kullanarak örtük değere erişmek mümkündür :
def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
xs zip ys map { t => implicitly[Numeric[T]].times(t._1, t._2) }
veya
def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
xs zip ys map { t => context[T]().times(t._1, t._2) }