2013-12-14 17 views
9

này hoạt động tốtKhông ClassTag sẵn cho MyClass.this.T cho một loại trừu tượng

class MyClass[T<: Actor: ClassTag] extends Actor { 
    //.... 
} 

nhưng điều này không do lỗi No ClassTag available for MyClass.this.T

class MyClass extends Actor { 
    type T<: Actor 
    //... 
} 

ngay cả khi làm như sau:

class MyClass extends Actor { 
    type T<: Actor: ClassTag //this doesn't even compile 
    //... 
} 

Làm cách nào để sử dụng tóm tắt type và loại bỏ lỗi?

Trả lời

8
class M[A <: B: C] 

là viết tắt của

class M[A <: B](implicit c: C[A]) 

Do đó, nếu bạn di chuyển A đến một thành viên loại trừu tượng, bạn sẽ phải viết một cái gì đó giống như

abstract class M { 
    type A <: B 
    implicit protected def c: C[A] 
} 

và đòi hỏi bất cứ ai thực hiện M để cung cấp chẳng hạn giá trị c. Nếu bạn muốn M không trừu tượng, bạn phải yêu cầu một tham số giá trị nhà xây dựng kiểu C[A], mà lần lượt có nghĩa là loại A phải loại constructor tham số ...


Sửa để trả lời các ý kiến: Các ký hiệu A : Cđược xác định là mở rộng thành thông số giá trị ẩn của loại C[A]. Có C được gọi là bối cảnh ràng buộc, và nó có thể được hiểu như yêu cầu một loại lớp C[_] cho loại A. Nếu bạn triển khaiM bạn không cần phải lặp lại công cụ sửa đổi implicit. Tại sao nó lại ở đó? Để tôi cho bạn một ví dụ sử dụng một kiểu lớp nổi tiếng Ordering:

abstract class Foo { 
    type A 
    implicit protected def ord: Ordering[A] 

    protected def seq: Seq[A] 

    def range: (A, A) = { 
    val xs = seq 
    xs.min -> xs.max 
    } 
} 

Nếu bạn loại bỏ implicit, bạn sẽ phải thay đổi các cuộc gọi đến và xs.minxs.max đòi hỏi một tiềm ẩn Ordering.

object Bar extends Foo { 
    type A = Int 
    val seq = List(8, 34, 5, 21, 3, 13) 
    val ord = Ordering.Int // don't need to repeat `implicit` 
} 

Bar.range // (3, 34) 

Ở đây, Bar cho biết cách bạn cung cấp thông số giá trị ẩn. Đây sẽ là giống nhau cho ClassTag:

trait MyClass { 
    type A 
    implicit def tag: reflect.ClassTag[A] 
} 

object StringClass extends MyClass { 
    type A = String 
    // type String is statically known, thus compiler gives us this: 
    val tag = reflect.classTag[String] 
} 

Nếu lớp con của bạn là generic lại, bạn sẽ cần phải vượt qua về trách nhiệm trong việc cung cấp một thẻ lớp:

class GenericClass[A1](implicit val tag: reflect.ClassTag[A1]) { 
    type A = A1 
} 
+0

Thú vị. Tôi chơi xung quanh với nó một chút, và hai câu hỏi phát sinh: 1) Tại sao phương thức 'c' trong' M' * ngầm *:? Không phải là một phương pháp không tiềm ẩn tương đương với hai phiên bản trước sử dụng các loại parametrized? 2) Trong trường hợp đặc biệt của một 'ClassTag' một giá trị constructor là không cần thiết (tôi thay thế nó bằng' override val c = classTag [...] 'trong lớp). Điều này có thường không? – Beryllium

+0

Tôi làm cách nào để cung cấp việc triển khai 'c: ClassTag' trong các lớp con? Nó nên trông giống cái gì? –

+0

có vẻ như có sự lặp lại dư thừa trong 'đối tượng StringClass mở rộng MyClass' - loại A =' Chuỗi' và thẻ val = reflect.classTag ['String']? Tôi có thể tránh điều này không? –

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