Scala'da Manifest nedir ve ne zaman ihtiyacınız var?


133

Scala 2.7.2'den bu yana ManifestJava'nın tür silme işlemi için geçici çözüm olarak adlandırılan bir şey var. Fakat Manifesttam olarak nasıl çalışır ve onu neden / ne zaman kullanmanız gerekir?

Jorge Ortiz'in Manifests: Reified Types blog yazısı bazılarını açıklıyor, ancak bağlam sınırlarıyla birlikte nasıl kullanılacağını açıklamıyor .

Ayrıca, aradaki ClassManifestfark Manifestnedir?

Yazım silme ile ilgili bazı uyarıları olan bazı kodum var (daha büyük bir programın parçası, buraya kolayca ekleyemiyorum); Bunları bildirimler kullanarak çözebileceğimi sanıyorum, ancak tam olarak nasıl olduğundan emin değilim.


2
Posta listesinde Manifest / ClassManifest farkı hakkında bir tartışma oldu, bkz. Scala-programming-language.1934581.n4.nabble.com/…
Arjan Blokzijl

Yanıtlar:


198

Derleyici, türler hakkında JVM çalışma zamanının kolayca gösterebileceğinden daha fazla bilgi bilir. Manifest, derleyicinin, kaybolan tür bilgileri hakkında çalışma zamanında koda bir boyutlar arası mesaj göndermesinin bir yoludur.

Bu, Klepton'luların fosil kayıtlarında ve insanların "hurda" DNA'sında şifreli mesajlar bırakmalarına benzer. Işık hızının ve yerçekimi rezonans alanlarının sınırlamaları nedeniyle, doğrudan iletişim kuramazlar. Ancak, sinyallerini nasıl ayarlayacağınızı biliyorsanız, öğle yemeğinde ne yiyeceğinize veya hangi loto numarasını oynayacağınıza karar vermekten hayal edemeyeceğiniz şekillerde yararlanabilirsiniz.

Bir Manifest'in, daha fazla ayrıntı bilmeden gördüğünüz hatalara fayda sağlayıp sağlamayacağı açık değildir.

Manifestlerin yaygın bir kullanımı, kodunuzun bir koleksiyonun statik türüne göre farklı şekilde davranmasını sağlamaktır. Örneğin, bir List [Dize] 'yi diğer Liste türlerinden farklı bir şekilde ele almak isterseniz:

 def foo[T](x: List[T])(implicit m: Manifest[T]) = {
    if (m <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

  foo(List("one", "two")) // Hey, this list is full of strings
  foo(List(1, 2)) // Non-stringy list
  foo(List("one", 2)) // Non-stringy list

Buna yansıma temelli bir çözüm, muhtemelen listenin her bir unsurunun incelenmesini içerecektir.

Bağlam bağı, scala'da tür sınıflarını kullanmak için en uygun görünmektedir ve burada Debasish Ghosh tarafından iyi bir şekilde açıklanmıştır: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

Bağlam sınırları, yöntem imzalarını daha okunaklı hale de getirebilir. Örneğin, yukarıdaki işlev, aşağıdaki gibi bağlam sınırları kullanılarak yeniden yazılabilir:

  def foo[T: Manifest](x: List[T]) = {
    if (manifest[T] <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

25

Tam bir cevap değil, ancak Manifestve arasındaki farkla ilgili ClassManifestolarak, Scala 2.8 Arraymakalesinde bir örnek bulabilirsiniz :

Geriye kalan tek soru, genel dizi oluşturmanın nasıl uygulanacağıdır. Java farklı Scala bir örnek oluşturma Yeni sağlar tip bir parametredir. Java'da tek tip bir dizi gösterimi olmadığı gerçeği göz önüne alındığında, bu nasıl uygulanabilir? Array[T]T

Bunu yapmanın tek yolu, türü tanımlayan ek çalışma zamanı bilgisi gerektirmektir T. Scala 2.8'in bunun için Manifest adı verilen yeni bir mekanizması var . Bir tür nesnesi, tür Manifest[T]hakkında tam bilgi sağlar T.
Manifestdeğerler tipik olarak örtük parametrelerde geçirilir; ve derleyici statik olarak bilinen türler için bunları nasıl oluşturacağını bilir T.

Bir de söz konusudur zayıf formu adında ClassManifestmutlaka tüm argüman türlerini bilmeden, bir tür sadece üst düzey sınıf bilerek inşa edilebilir .
Dizi oluşturmak için gerekli olan bu tür çalışma zamanı bilgisidir.

Misal:

Bu bilgiyi ClassManifest[T]yönteme örtük bir parametre olarak geçirerek sağlamak 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 steno biçimi olarak, Tbunun yerine type parametresinde bir bağlam sınırı1 kullanılabilir ,

( Örnek için bu SO sorusuna bakın )

, veren:

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 
} 

Scala derleyicisi Int, veya String, veya gibi bir tür üzerinde tabulate çağrılırken, tabüle List[T]etmek için örtük bağımsız değişken olarak iletilecek bir sınıf bildirimi oluşturabilir.


25

Bir Manifest, JVM'de (jenerikleri desteklemeyen) çalıştırmak için türden silinen jenerik türleri yeniden tanımlamayı amaçladı. Ancak bazı ciddi sorunları vardı: çok basitti ve Scala'nın tip sistemini tam olarak destekleyemiyorlardı. Bu nedenle Scala 2.10'da kullanımdan kaldırılmış ve TypeTags ile değiştirilmiştir (esasen Scala derleyicisinin türleri temsil etmek için kullandığı ve bu nedenle Scala türlerini tam olarak desteklediği şeydir). Farkla ilgili daha fazla ayrıntı için bkz .:

Diğer bir deyişle

ne zaman ihtiyacın var

2013-01-04'ten önce, Scala 2.10 piyasaya çıktığında .


Henüz kullanımdan kaldırılmadı (ama olacak), çünkü Scala yansıması 2.10'da hala deneysel.
Keros

2013-01-04'ten önce veya buna dayanan bir API kullanıyorsanız.
David Moles

1

En de dışarı chck Let manifestiçinde scalakaynaklardan ( Manifest.scala), gördüğümüz:

Manifest.scala:
def manifest[T](implicit m: Manifest[T])           = m

Aşağıdaki örnek kodla ilgili olarak:

def foo[A](somelist: List[A])(implicit m: Manifest[A]): String = {
  if (m <:< manifest[String]) {
    "its a string"
  } else {
    "its not a string"
  }
}

biz görebilirsiniz manifest functionörtük arar m: Manifest[T]tatmin hangi type parametero bizim örnek kodda sağlamak oldu manifest[String]. Yani şöyle bir şey aradığınızda:

if (m <:< manifest[String]) {

Geçerli eğer kontrol ediyoruz implicit mFonksiyonunuzda tanımlanan tiptedir manifest[String]ve aynı manifesttürde bir fonksiyonudur manifest[T]bir spesifik arayacaklarını manifest[String]ve böyle bir örtük varsa o bulur.

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.