2013-04-30 22 views
6

Herhangi bir boyutta bir tuple ve bir indeksle birlikte giren bir Scala metodu yazmayı umuyorum ve bu endekste tuple'daki elemanı döndürür. Her şeyi nasıl yapacağımı biliyorum ama türü koru. Dönüş değerinin, tuple öğesinin dinamik türünde olmasını sağlamak için henüz bir yol bulamadım.Scala'da dinamik türü koruyan tuple'lar için genel getto yöntemi mi?

def subscript_get(tup: Product, index:Int): Any={ 
    return tup.productElement(index)  
} 

örneğin kullanım olacaktır:

subscript_get((0,1,2,3),0) --> Int = 0

subscript_get((0,1,"asdf",3),2) --> java.lang.String = asdf

Ben geri sonucunu döküm biliyor İşte

var bugüne kadar fonksiyonudur daha sonra aradığım şey için, ama bu benim için işe yaramıyor çünkü her zaman ne tür bir oyuncu olduğumu bilmiyorum.

Böyle bir şey mümkün mü? Teşekkürler!

+0

Makrolar ile 2.10'da yapmak mümkündür, ancak sadece literal 'index' argümanları için (ve sadece [this] nedeniyle (http://stackoverflow.com/q/13669974/334519)" biraz tuhaf " amaçlanan "davranış". –

+0

Makrolara bakılmaksızın, statik olarak mevcut olan dinamik tip bilgisini vermek hakkında konuşmak hiç de saçmadır. –

+1

@TravisBrown, tam kullanımlı çağrı siteleri için size iyi bir yanıt verdi. "Subscript_get" için gayri-resmi olmayan çağrı siteleri için aklınızda neler olduğuna dair bazı örnekler verebilir misiniz? Özellikle, yukarıdaki imzada 'Ürün'ü kullanıyorsunuz, çünkü türün çalışma zamanına kadar ertelenmesini gerçekten istiyorsunuz, yoksa derleme zamanında tüm olası ürün türleri üzerinde soyutlamak istediğiniz için kullanıyor musunuz? –

cevap

0

Bunu yapamazsınız. Product kullanırsanız, tupllerdeki (derleme zamanı) değerlerin türü kaybolur. Ayrıca, bir yöntem, dönüş türünü, geçiş yaptığınız bir değere göre (tam olarak doğru değil, bkz. dependent method types, ancak Int için doğru) uyarlayamaz.

subscript_get(..., 1) match { 
    case v: Int => // do something with Int 
    case v: String => // do something with String 
    // snip 
    case _ => sys.error("don't know how to handle this") 
} 
11

Sana makro kullanan bir çözüm istediğinden emin değilim, ama kayıt için (ve o zamandan beri ben: Eğer desen eşleştirme kullanabilirsiniz

Eğer yayın yapmak için ne tür bilmiyorsanız, ve bu yöntemi daha önce kesin olarak yazdıysanız, 2.10'daki makro sistem ile bunu nasıl uygulayabileceğinizi burada bulabilirsiniz.

Yukarıdaki yorumda belirtildiği gibi, bu yaklaşım tamsayı olması için index gerektirir ve 2.10'da "underspecified but intended" behavior'a dayanır. Ayrıca belge hakkında some tricky questions'u yükseltir.

import scala.language.experimental.macros 
import scala.reflect.macros.Context 

object ProductIndexer { 
    def at[T <: Product](t: T)(index: Int) = macro at_impl[T] 
    def at_impl[T <: Product: c.WeakTypeTag](c: Context) 
    (t: c.Expr[T])(index: c.Expr[Int]) = { 
    import c.universe._ 

    index.tree match { 
     case Literal(Constant(n: Int)) if 
     n >= 0 && 
     weakTypeOf[T].members.exists { 
      case m: MethodSymbol => m.name.decoded == "_" + (n + 1).toString 
      case _ => false 
     } => c.Expr[Any](Select(t.tree, newTermName("_" + (n + 1).toString))) 
     case Literal(Constant(_: Int)) => c.abort(
     c.enclosingPosition, 
     "There is no element at the specified index!" 
    ) 
     case _ => c.abort(
     c.enclosingPosition, 
     "You must provide an integer literal!" 
    ) 
    } 
    } 
} 

Ve sonra:

scala> import ProductIndexer._ 
import ProductIndexer._ 

scala> val triple = (1, 'a, "a") 
triple: (Int, Symbol, String) = (1,'a,a) 

scala> at(triple)(0) 
res0: Int = 1 

scala> at(triple)(1) 
res1: Symbol = 'a 

scala> at(triple)(2) 
res2: String = a 

Tüm statik olarak beklendiği gibi yazılan ve bunu (veya bir hazır), aralık dışında bir dizin verirseniz, güzel bir derleme zamanı hatası alıyorum.

+0

Bu gerçekten çok hoş. Çok kötü, literals gerektirir. Endeksin değeri ile ilgili gizli kanıtlar kullanamadık mı? : P – gzm0

İlgili konular