2012-06-13 33 views
27

Với API phản chiếu mới của Scala, bạn có thể tham chiếu đến đối tượng đồng hành của lớp không? Tôi đang suy nghĩ điều gì đó dọc theo các dòng sau:Lấy đối tượng đối tượng đồng hành với API phản chiếu Scala mới

trait Base { 
    def companion: MetaBase = someReflectionMagic(this).asInstanceOf[MetaBase] 
} 

trait MetaBase { 
    // stuff 
} 

// --- 

class Foo extends Base 

object Foo extends MetaBase 

assert(new Foo.companion == Foo) 
+0

Tôi nghĩ bạn có thể có được một số thứ như thế này http://stackoverflow.com/questions/1913092/getting-object-instance-by-string-name-in-scala – Noah

+3

Tôi đã hy vọng điều gì đó sạch hơn, sử dụng API phản chiếu mới. – leedm777

Trả lời

37

Dave! Cảm ơn bạn đã quan tâm đến sự phản chiếu mới. Những người chấp nhận sớm đã thúc đẩy quá trình phát triển của sự phản ánh và các macro đến một mức độ đáng kể, và tôi rất hạnh phúc khi trở thành một phần của cộng đồng tuyệt vời của chúng tôi.

Trước khi trả lời câu hỏi của bạn, tôi muốn bắt đầu với tuyên bố từ chối trách nhiệm. Trong phiên bản 2.10.0-M4, chúng ta vừa đặt nền móng của API phản chiếu Scala. Nó vẫn còn nóng ra khỏi báo chí, do đó, các tài liệu rất khan hiếm và API là không chính xác thủng với tiện nghi. Nó hoạt động, nhưng nó đòi hỏi phải thử nghiệm và phản hồi. Chắc chắn, rối tung với các API tiền phát hành là rắc rối, nhưng tôi luôn ở đây để trợ giúp.

Cho đến nay chúng tôi có dự thảo về những gì trong tương lai sẽ trở thành SIP phản chiếu: https://docs.google.com/document/d/1Z1VhhNPplbUpaZPIYdc0_EUv5RiGQ2X4oqp0i-vz1qw/edit#heading=h.pqwdkl1226tc. Bạn có thể đọc nó ngay lập tức, hoặc đầu tiên có thể lướt qua câu trả lời của tôi dưới đây.

trait Base { 
    def companion: MetaBase = { 
    // runtime reflection is typically done 
    // by importing things from scala.reflect.runtime package 
    import scala.reflect.runtime._ 

    // the new Scala reflection API is mirror based 
    // mirrors constitute a hierarchy of objects 
    // that closely follows the hierarchy of the things they reflect 
    // for example, for a class you'll have a ClassMirror 
    // for a method you'll have a MethodMirror and so on 
    // why go the extra mile? 
    // because this provides more flexibility than traditional approaches 
    // you can read more about mirror-based designs here: 
    // https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/mirrors.pdf 
    // https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/reflecting-scala.pdf 

    // bottom line is that to do anything you will need a mirror 
    // for example, in your case, you need a ClassMirror 

    // remember I said that mirrors provide more flexibility? 
    // for one, this means that mirror-based reflection facilities 
    // might have multiple implementations 
    // in a paper linked above, Gilad Bracha muses over a runtime 
    // that loads things remotely over the network 
    // in our case we might have different mirrors for JVM and CLR 
    // well, anyways 

    // the canonical (and the only one now) implementation of the mirror API 
    // is Java-based reflection that uses out of the box classloaders 
    // here's its root: https://github.com/scalamacros/kepler/blob/9f71e9f114c10b52350c6c4ec757159f06e55daa/src/reflect/scala/reflect/api/Mirrors.scala#L178 
    // yeah, right, I've just linked a source file from trunk 
    // we'll have Scaladocs for that soon, but for now take a look 
    // this file is interfaces-only and is heavy on comments 

    // to start with Java-based reflection implementation you need a classloader 
    // let's grab one and instantiate the root mirror 
    // btw, the same effect could be achieved by writing 
    // `scala.reflect.runtime.currentMirror` 
    val rootMirror = universe.runtimeMirror(getClass.getClassLoader) 

    // now when we've finally entered the reflective world 
    // we can get the stuff done 
    // first we obtain a ClassSymbol that corresponds to the current instance 
    // (ClassSymbols are to Scala the same as Classes are to Java) 
    var classSymbol = rootMirror.classSymbol(getClass) 

    // having a Scala reflection entity 
    // we can obtain its reflection using the rootMirror 
    val classMirror = rootMirror.reflectClass(classSymbol) 

    // now we just traverse the conceptual hierarchy of mirrors 
    // that closely follows the hierarchy of Scala reflection concepts 
    // for example, a ClassMirror has a companion ModuleMirror and vice versa 
    val moduleMirror = classMirror.companion.get 

    // finally, we've arrived at our destination 
    moduleMirror.instance.asInstanceOf[MetaBase] 
    } 
} 

trait MetaBase { 
    // stuff 
} 

// --- 

class Foo extends Base 

object Foo extends MetaBase 

object Test extends App { 
    assert(new Foo().companion == Foo) 
} 

Cập nhật. Xin vui lòng xem bài viết tuyệt vời của Daniel Sobral: http://dcsobral.blogspot.ch/2012/07/json-serialization-with-reflection-in.html.

+0

Nhìn vào [câu hỏi này] (http://stackoverflow.com/q/10893712/53013) là tốt - mặc dù có một câu trả lời ở đó có vẻ tốt. –

+0

Làm thế nào để cập nhật mã này để làm cho nó hoạt động trong scala 2.10.0 final? –

+3

https://gist.github.com/xeno-by/4985929 –

5

Tôi không thấy nhận xét cuối cùng của Eugene và nghĩ ra điều này. Nó hoạt động cho scala 2.10.

trait ReflectionSugars{ 
    import scala.reflect.runtime.{universe => ru} 
    private lazy val universeMirror = ru.runtimeMirror(getClass.getClassLoader) 

    def companionOf[T](implicit tt: ru.TypeTag[T]) = { 
    val companionMirror = universeMirror.reflectModule(ru.typeOf[T].typeSymbol.companionSymbol.asModule) 
    companionMirror.instance 
    } 

} 

trait X extends ReflectionSugars{ 
    def companion = companionOf[X] 
} 

https://gist.github.com/piotrga/5928581

Tôi hy vọng điều này sẽ giúp!

Các vấn đề liên quan