2009-12-16 39 views
22

Tôi cần đối tượng (hoặc "đối tượng đơn lẻ" hoặc "đối tượng đồng hành" ... bất kỳ thứ gì ngoài lớp) được xác định bằng tên chuỗi. Nói cách khác, nếu tôi có:Lấy cá thể đối tượng bằng tên chuỗi trong scala

package myPackage 
object myObject 

... sau đó là có bất cứ điều gì như thế này:

GetSingletonObjectByName("myPackage.myObject") match { 
    case instance: myPackage.myObject => "instance is what I wanted" 
} 

Trả lời

12

Scala vẫn còn thiếu một API phản chiếu. Bạn có thể lấy một thể hiện của đối tượng bạn đồng hành bằng cách tải các lớp đối tượng đồng:

import scala.reflect._ 
def companion[T](implicit man: Manifest[T]) : T = 
    man.erasure.getField("MODULE$").get(man.erasure).asInstanceOf[T] 


scala> companion[List$].make(3, "s") 
res0: List[Any] = List(s, s, s) 

Để có được người bạn đồng hành không định kiểu đối tượng, bạn có thể sử dụng lớp trực tiếp:

import scala.reflect.Manifest 
def companionObj[T](implicit man: Manifest[T]) = { 
    val c = Class.forName(man.erasure.getName + "$") 
    c.getField("MODULE$").get(c) 
} 


scala> companionObj[List[Int]].asInstanceOf[List$].make(3, "s") 
res0: List[Any] = List(s, s, s) 

này phụ thuộc vào đường đi scala được ánh xạ tới các lớp java.

+1

bò Thánh này. Bạn có biết cú pháp này là một phần cố định của thông số kỹ thuật Scala hay không (dù đã được sửa như bất kỳ thứ gì khác trong ngôn ngữ)? Nó có vẻ như một ý tưởng tồi để dựa vào điều này. Và vì mục tiêu của tôi là làm cho mã * rõ ràng hơn * ... Cảm ơn bạn! – Dave

+0

Như ông đã đề cập, không có API phản chiếu trong Scala, vì vậy cho dù điều này được bao phủ bởi các spec Scala hay không, đây là cách duy nhất để bạn làm điều đó. Tôi nhận thấy câu hỏi/câu trả lời này đã hơn một tuổi, có bất kỳ tin tức nào ở đây không? – pdinklag

1

Chặn các thủ thuật phản chiếu, bạn không thể. Lưu ý, ví dụ, cách phương thức companion được định nghĩa trên các bộ sưu tập Scala 2.8 - nó có như vậy một thể hiện của một lớp có thể nhận được đối tượng đồng hành, nếu không thì không thể.

+0

Bạn có thể thêm liên kết tới nguồn không? –

+0

http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala, tuy nhiên, hy vọng, Scaladoc 2 của 2.8 sẽ sớm chứa các liên kết đến nguồn, như đã xảy ra với 2.7. –

11

Điều chỉnh câu trả lời của Thomas Jung ở trên: bạn sẽ làm tốt hơn để nói bạn đồng hành [List.type] vì a) đây phải là cách ổn định để tham chiếu, không phụ thuộc vào lược đồ mang tên và b) các loại chưa được lọc.

def singleton[T](implicit man: reflect.Manifest[T]) = { 
    val name = man.erasure.getName() 
    assert(name endsWith "$", "Not an object: " + name) 
    val clazz = java.lang.Class.forName(name) 

    clazz.getField("MODULE$").get(clazz).asInstanceOf[T] 
} 

scala> singleton[List.type].make(3, "a")      
res0: List[java.lang.String] = List(a, a, a) 
+0

Rất đẹp! Vẫn còn một chút hào hứng cho thị hiếu của tôi nhưng tôi có thể sử dụng ... – Dave

+0

Làm thế nào là điều này tốt hơn so với chỉ 'List.make (3," a ")'? OP muốn lấy đối tượng theo tên chuỗi – IttayD

+1

Cảm ơn! Điều này thật đúng với gì mà tôi đã tìm kiếm. Nó chắc chắn là một hack, nhưng ít bẩn hơn những gì tôi quản lý để đến với. –

34

Trong scala 2.10 chúng ta có thể làm như

import scala.reflect.runtime.universe 

val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader) 

val module = runtimeMirror.staticModule("package.ObjectName") 

val obj = runtimeMirror.reflectModule(module) 

println(obj.instance) 
Các vấn đề liên quan