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.min
xs.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
}
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
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ì? –
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? –