2012-02-07 33 views
25

Điều tôi đang cố làm là tạo một hàm có thể sử dụng một lớp chung và sử dụng một phương thức tĩnh trong nó (xin lỗi ngôn ngữ Java).).Nhận đối tượng đồng hành của lớp theo kiểu chung chung Scala

trait Worker {def doSth: Unit} 

class Base 

object Base extends Worker 

// this actually wouldn't work, just to show what I'm trying to achieve 
def callSthStatic[T that companion object is <: Worker](implicit m: Manifest[T]) { 
    // here I want to call T.doSth (on T object) 
    m.getMagicallyCompanionObject.doSth 
} 

Bất kỳ ý tưởng nào?

Trả lời

20

A gist by Miles Sabin có thể cung cấp cho bạn một gợi ý:

trait Companion[T] { 
    type C 
    def apply() : C 
} 

object Companion { 
    implicit def companion[T](implicit comp : Companion[T]) = comp() 
} 

object TestCompanion { 
    trait Foo 

    object Foo { 
    def bar = "wibble" 

    // Per-companion boilerplate for access via implicit resolution 
    implicit def companion = new Companion[Foo] { 
     type C = Foo.type 
     def apply() = Foo 
    } 
    } 

    import Companion._ 

    val fc = companion[Foo] // Type is Foo.type 
    val s = fc.bar   // bar is accessible 
} 

này nên được biên soạn với -Ydependent-method-types cờ nếu sử dụng Scala 2.9.x.

+0

Tôi đã thêm nội dung Gist thực tế - Gist có thể biến mất và liên kết đó đủ điều kiện làm nhận xét. –

+0

Tôi nhận được "lỗi: loại phương pháp phụ thuộc bất hợp pháp đồng hành không xác định" [T] (comp ngầm: Companion [T]) = comp.apply() "tại dòng" ngầm định đồng hành [T] (ẩn comp: Companion [ T]) = comp() "với scala 2.9.1. Tôi có làm sai không? :-) –

+3

Tôi sẽ thêm parenthetically rằng nếu loại 'Foo' là có thể nhìn thấy sau đó vì vậy nó là đối tượng đồng hành, vì vậy mặc dù điều này có vẻ khá tiện lợi Tôi không nghĩ rằng nó hữu ích trong thực tế. –

7

Bạn có thể sử dụng sự phản chiếu để có được lớp đồng hành và thể hiện của nó, nhưng điều đó phụ thuộc vào nội bộ Scala có thể thay đổi trong tương lai xa (?). Và không có loại an toàn khi bạn nhận được một AnyRef. Nhưng không cần phải thêm bất kỳ sự can thiệp nào vào các lớp và các đối tượng của bạn.

def companionOf[T : Manifest] : Option[AnyRef] = try{ 
    val classOfT = implicitly[Manifest[T]].erasure 
    val companionClassName = classOfT.getName + "$" 
    val companionClass = Class.forName(companionClassName) 
    val moduleField = companionClass.getField("MODULE$") 
    Some(moduleField.get(null)) 
} catch { 
    case e => None 
} 

case class A(i : Int) 

companionOf[A].collect{case a : A.type => a(1)} 
// res1: Option[A] = Some(A(1)) 
+0

Cảm ơn, phản ánh sẽ giải quyết vấn đề ... cho đến khi cập nhật phiên bản scala, vì tên của đối tượng đồng hành không được hứa sẽ được giữ theo cách này. –

+1

Vâng, đó là sự thật. Nhưng tôi không nghĩ rằng việc đặt tên sẽ thay đổi bất cứ lúc nào sớm, kể từ khi hội nghị này kéo dài ít nhất kể từ đầu Scala 2.x ngày. – MxFr

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