Được đóng hộp trong ví dụ này, phải không?
scala> typeOnly[java.lang.Double](vs)
res1: Seq[Double] = List(2.3)
Cập nhật: oracle là phù hợp khó hiểu: "boxing is supposed to be invisible, plus or minus". Tôi không biết nếu trường hợp này là cộng hoặc trừ.
ý thức của tôi là nó là một lỗi, bởi vì nếu không thì đó là tất cả một trò chơi trống.
Xem thêm phân biệt theo định dạng: "Tôi không biết ví dụ đã cho là gì." Lưu ý rằng nó không được chỉ định, được mong đợi bởi ai.
Đây là một bài tập hữu ích trong việc hỏi ai biết về đóng hộp, và các hộp là gì? Nó giống như trình biên dịch là một pháp sư làm việc chăm chỉ để che giấu một sợi dây mà giữ một thẻ chơi treo lơ lửng trong không trung, mặc dù mọi người xem đã biết rằng phải có một sợi dây.
scala> def f[A](s: Seq[Any])(implicit t: ClassTag[A]) = s collect {
| case v if t.runtimeClass.isPrimitive &&
| ScalaRunTime.isAnyVal(v) &&
| v.getClass.getField("TYPE").get(null) == t.runtimeClass =>
| v.asInstanceOf[A]
| case t(x) => x
| }
f: [A](s: Seq[Any])(implicit t: scala.reflect.ClassTag[A])Seq[A]
scala> f[Double](List(1,'a',(),"hi",2.3,4,3.14,(),'b'))
res45: Seq[Double] = List(2.3, 3.14)
ScalaRunTime
không được hỗ trợ API - cuộc gọi đến isAnyVal
chỉ là một trận đấu trên các loại; người ta cũng có thể chỉ cần kiểm tra rằng trường "TYPE" tồn tại hay
Try(v.getClass.getField("TYPE").get(null)).map(_ == t.runtimeClass).getOrElse(false)
Nhưng để có được trở lại một đẹp một liner, bạn có thể cuộn của riêng bạn ClassTag
để xử lý các nhổ đặc biệt-cased.
Phiên bản dành cho 2.11. Điều này có thể không được chảy máu cạnh, nhưng đó là cạnh cauterized gần đây.
object Test extends App {
implicit class Printable(val s: Any) extends AnyVal {
def print = Console println s.toString
}
import scala.reflect.{ ClassTag, classTag }
import scala.runtime.ScalaRunTime
case class Foo(s: String)
val vs = List(1,'a',(),"hi",2.3,4,Foo("big"),3.14,Foo("small"),(),null,'b',null)
class MyTag[A](val t: ClassTag[A]) extends ClassTag[A] {
override def runtimeClass = t.runtimeClass
/*
override def unapply(x: Any): Option[A] = (
if (t.runtimeClass.isPrimitive && (ScalaRunTime isAnyVal x) &&
x.getClass.getField("TYPE").get(null) == t.runtimeClass)
Some(x.asInstanceOf[A])
else super.unapply(x)
)
*/
override def unapply(x: Any): Option[A] = (
if (t.runtimeClass.isPrimitive) {
val ok = x match {
case _: java.lang.Integer => runtimeClass == java.lang.Integer.TYPE
//case _: java.lang.Double => runtimeClass == java.lang.Double.TYPE
case _: java.lang.Double => t == ClassTag.Double // equivalent
case _: java.lang.Long => runtimeClass == java.lang.Long.TYPE
case _: java.lang.Character => runtimeClass == java.lang.Character.TYPE
case _: java.lang.Float => runtimeClass == java.lang.Float.TYPE
case _: java.lang.Byte => runtimeClass == java.lang.Byte.TYPE
case _: java.lang.Short => runtimeClass == java.lang.Short.TYPE
case _: java.lang.Boolean => runtimeClass == java.lang.Boolean.TYPE
case _: Unit => runtimeClass == java.lang.Void.TYPE
case _ => false // super.unapply(x).isDefined
}
if (ok) Some(x.asInstanceOf[A]) else None
} else if (x == null) { // let them collect nulls, for example
if (t == ClassTag.Null) Some(null.asInstanceOf[A]) else None
} else super.unapply(x)
)
}
implicit def mytag[A](implicit t: ClassTag[A]): MyTag[A] = new MyTag(t)
// the one-liner
def g[A](s: Seq[Any])(implicit t: ClassTag[A]) = s collect { case t(x) => x }
// this version loses the "null extraction", if that's a legitimate concept
//def g[A](s: Seq[Any])(implicit t: ClassTag[A]) = s collect { case x: A => x }
g[Double](vs).print
g[Int](vs).print
g[Unit](vs).print
g[String](vs).print
g[Foo](vs).print
g[Null](vs).print
}
Đối với 2.10.x, dòng phụ thêm của boilerplate vì độ phân giải ngầm - tốt, chúng tôi sẽ không nói nó bị hỏng, chúng tôi sẽ chỉ nói nó không hoạt động.
// simplified version for 2.10.x
object Test extends App {
implicit class Printable(val s: Any) extends AnyVal {
def print = Console println s.toString
}
case class Foo(s: String)
val vs = List(1,'a',(),"hi",2.3,4,Foo("big"),3.14,Foo("small"),(),null,'b',null)
import scala.reflect.{ ClassTag, classTag }
import scala.runtime.ScalaRunTime
// is a ClassTag for implicit use in case x: A
class MyTag[A](val t: ClassTag[A]) extends ClassTag[A] {
override def runtimeClass = t.runtimeClass
override def unapply(x: Any): Option[A] = (
if (t.runtimeClass.isPrimitive && (ScalaRunTime isAnyVal x) &&
(x.getClass getField "TYPE" get null) == t.runtimeClass)
Some(x.asInstanceOf[A])
else t unapply x
)
}
// point of the exercise in implicits is the type pattern.
// there is no need to neutralize the incoming implicit by shadowing.
def g[A](s: Seq[Any])(implicit t: ClassTag[A]) = {
implicit val u = new MyTag(t) // preferred as more specific
s collect { case x: A => x }
}
s"Doubles? ${g[Double](vs)}".print
s"Ints? ${g[Int](vs)}".print
s"Units? ${g[Unit](vs)}".print
s"Strings? ${g[String](vs)}".print
s"Foos? ${g[Foo](vs)}".print
}
Thúc đẩy bình luận:
@WilfredSpringer Có người nghe bạn. SI-6967
Có, nhưng tôi muốn tự động bao gồm trường hợp này thay vì yêu cầu sử dụng loại đóng hộp làm thông số. –
Thật không may tôi không nghĩ rằng có một giải pháp tốt cho vấn đề này. Bạn có thể thấy một số vấn đề bạn sẽ gặp phải [ở đây] (http://stackoverflow.com/questions/13233728/scala-2-10-typetag-usage/13234888#13234888). Bạn có thể có thể sử dụng thẻ loại và một gương mẫu để làm những gì bạn muốn, nhưng nó chắc chắn sẽ không được thanh lịch. –
'.getClass.getField (" TYPE "). Nhận (null)' là thông minh; Tôi đã tìm kiếm một phương pháp đơn giản để phù hợp với một lớp đóng hộp/loại/biểu tượng/... để nguyên thủy của nó mà không có sự phù hợp với mô hình lớn, nhưng không có may mắn cho đến nay. – gourlaysama