Tôi đang cố gắng viết một số phương pháp mở rộng cho các bộ sưu tập Scala, và gặp rắc rối khi phát huy chúng hoàn toàn.Làm cách nào để sử dụng loại thành viên A trong IsTraversableLike?
Một nỗ lực đầu tiên tại tailOption mang lại một cái gì đó như:
implicit class TailOption[A, Repr <: GenTraversableLike[A, Repr]](val repr: Repr) {
def tailOption: Option[Repr] =
if (repr.isEmpty) None
else Some(repr.tail)
}
không may, điều này không làm việc:
scala> List(1,2,3).tailOption
<console>:19: error: value tailOption is not a member of List[Int]
List(1,2,3).tailOption
Scala 2.10 cung cấp IsTraversableLike kiểu lớp để giúp thích nghi với các loại điều này cho tất cả các bộ sưu tập (kể cả các bộ sưu tập lẻ, chẳng hạn như Strings).
Với điều này tôi có thể ví dụ như thực hiện tailOption khá dễ dàng:
implicit class TailOption[Repr](val r: Repr)(implicit fr: IsTraversableLike[Repr]) {
def tailOption: Option[Repr] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.tail)
}
}
scala> List(1,2,3).tailOption
res12: Option[List[Int]] = Some(List(2, 3))
scala> "one".tailOption
res13: Option[String] = Some(ne)
Kết quả là của đúng loại: Option[<input-type>]
. Cụ thể, tôi đã có thể bảo toàn loại Repr
khi gọi các phương thức trả lại Repr
, như `đuôi.
Thật không may, tôi dường như không thể sử dụng mẹo này để giữ nguyên loại yếu tố của bộ sưu tập. Tôi không thể gọi các phương thức trả về một phần tử.
IsTraversableLike
không có thành viên A nhưng có vẻ như không hữu ích. Đặc biệt, tôi không thể tái tạo lại kiểu phần tử gốc của mình và thành viên không tương đương với kiểu. Ví dụ, không có việc làm thêm, headTailOption
trông như thế này:
implicit class HeadTailOption[Repr](val r: Repr)(implicit val fr: IsTraversableLike[Repr]) {
def headTailOption: Option[(fr.A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
scala> val Some((c, _)) = "one".headTailOption
c: _1.fr.A forSome { val _1: HeadTailOption[String] } = o
Như chúng ta có thể thấy, c có một loại tuyệt vời baroque. Nhưng, loại này là không tương đương với Char:
scala> val fr = implicitly[IsTraversableLike[String]]
fr: scala.collection.generic.IsTraversableLike[String] = [email protected]
scala> implicitly[fr.A <:< Char]
<console>:25: error: Cannot prove that fr.A <:< Char.
implicitly[fr.A <:< Char]
Tôi đã thử tất cả các loại thủ đoạn kể cả có Repr[A] <: GenTraversableLike[A, Repr[A]]
không ai trong số đó giúp đỡ. Bất cứ ai có thể làm ra nước sốt ma thuật để làm cho headTailOption
trả lại đúng loại cho:
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption
Bạn đã đánh bại tôi. Thật không may là sự phân chia giữa phương thức ngầm sử dụng kiểu phụ thuộc fr.A và lớp tham số kiểu là cần thiết ở đây, vì vậy tôi không tin rằng một giải pháp lớp ngầm định là (hiện tại) có thể. –
Vâng, tôi đã đi đến cùng một kết luận ngay bây giờ. Lớp ngầm định không có khả năng tái tạo kiểu chuyển đổi/suy luận kiểu cần thiết của kiểu phụ thuộc ... –