如何return通配符泛型?
How to return wildcard generic?
我有一个带有参数的类型别名,我想 return 来自一个方法的不同参数类型的实例:
type TC[T] = (ClassTag[T], Option[T])
def gen(x: Int): TC[_] = x match {
case 0 => (classTag[Int], Option[Int](0))
case _ => (classTag[String], Option[String](""))
}
这不起作用并给我错误:
error: type mismatch;
found : (scala.reflect.ClassTag[_ >: Int with String], Option[Any])
required: TC[]
(which expands to) (scala.reflect.ClassTag[], Option[_]) forSome { type _ }
我试过用Any
代替通配符_
,还是不行:
def gen(x: Int): TC[Any]
On line 2: error: type mismatch;
found : scala.reflect.ClassTag[Int]
required: scala.reflect.ClassTag[Any]
Note: Int <: Any, but trait ClassTag is invariant in type T.
You may wish to investigate a wildcard type such as _ <: Any
. (SLS 3.2.10)
case _ => (classTag[String], Some(""))
^
On line 3: error: type mismatch;
found : scala.reflect.ClassTag[String]
required: scala.reflect.ClassTag[Any]
Note: String <: Any, but trait ClassTag is invariant in type T.
You may wish to investigate a wildcard type such as _ <: Any
. (SLS 3.2.10)
如何实现?
return 特定类型比存在类型更好。如果你想要 gen
到 return 不同的类型取决于它的参数那么实际上 gen
是一个多态函数。尝试使用类型 class 和单例类型的以下方法。
type TC[T] = (ClassTag[T], Option[T])
trait Gen[X <: Int] {
type Out
def apply(x: X): Out
}
trait LowPriorityGen {
type Aux[X <: Int, Out0] = Gen[X] { type Out = Out0 }
def instance[X <: Int, Out0](f: X => Out0): Aux[X, Out0] = new Gen[X] {
override type Out = Out0
override def apply(x: X): Out0 = f(x)
}
implicit def default[X <: Int : ValueOf]: Aux[X, TC[String]] = instance(_ => (classTag[String], Option[String]("")))
}
object Gen extends LowPriorityGen {
implicit val zero: Aux[0, TC[Int]] = instance(_ => (classTag[Int], Option[Int](0)))
}
def gen[X <: Int with Singleton](x: X)(implicit g: Gen[X]): g.Out = g(x)
gen(0) //(Int,Some(0))
gen(1) //(java.lang.String,Some())
原因与中的相似。 ClassTag
和 Option
有不同的方差。
尝试
type TC[T] = (ClassTag[_ <: T], Option[T])
def gen(x: Int): TC[_] = x match {
case 0 => (classTag[Int], Option[Int](0))
case _ => (classTag[String], Option[String](""))
}
即使您无法在类型中编码所需的 属性,您仍然可以在编译时使用模式匹配右侧的 check
检查它。
def gen(x: Int): (ClassTag[_], Option[_]) = x match {
case 0 => check(classTag[Int], Option[Int](0))
case _ => check(classTag[String], Option[String](""))
}
def check[T](classTag: ClassTag[T], option: Option[T]): (ClassTag[T], Option[T]) = (classTag, option)
事实证明,因为 Tuple4
类型参数是协变的:Tuple4[+T1, +T2, +T3, +T4]
,它不能很好地与不变类型 class 一起使用,例如 ClassTag
.
我创建了一个采用不变类型参数的包装器 class:
case class TC[T](ct: ClassTag[T], o: Option[T])
def gen(x: Int): TC[_] = x match {
case 0 => TC(classTag[Int], Option[Int](0))
case _ => TC(classTag[String], Option[String](""))
}
瞧,它起作用了。
我有一个带有参数的类型别名,我想 return 来自一个方法的不同参数类型的实例:
type TC[T] = (ClassTag[T], Option[T])
def gen(x: Int): TC[_] = x match {
case 0 => (classTag[Int], Option[Int](0))
case _ => (classTag[String], Option[String](""))
}
这不起作用并给我错误:
error: type mismatch; found : (scala.reflect.ClassTag[_ >: Int with String], Option[Any]) required: TC[] (which expands to) (scala.reflect.ClassTag[], Option[_]) forSome { type _ }
我试过用Any
代替通配符_
,还是不行:
def gen(x: Int): TC[Any]
On line 2: error: type mismatch; found : scala.reflect.ClassTag[Int] required: scala.reflect.ClassTag[Any] Note: Int <: Any, but trait ClassTag is invariant in type T. You may wish to investigate a wildcard type such as
_ <: Any
. (SLS 3.2.10) case _ => (classTag[String], Some("")) ^ On line 3: error: type mismatch; found : scala.reflect.ClassTag[String] required: scala.reflect.ClassTag[Any] Note: String <: Any, but trait ClassTag is invariant in type T. You may wish to investigate a wildcard type such as_ <: Any
. (SLS 3.2.10)
如何实现?
return 特定类型比存在类型更好。如果你想要 gen
到 return 不同的类型取决于它的参数那么实际上 gen
是一个多态函数。尝试使用类型 class 和单例类型的以下方法。
type TC[T] = (ClassTag[T], Option[T])
trait Gen[X <: Int] {
type Out
def apply(x: X): Out
}
trait LowPriorityGen {
type Aux[X <: Int, Out0] = Gen[X] { type Out = Out0 }
def instance[X <: Int, Out0](f: X => Out0): Aux[X, Out0] = new Gen[X] {
override type Out = Out0
override def apply(x: X): Out0 = f(x)
}
implicit def default[X <: Int : ValueOf]: Aux[X, TC[String]] = instance(_ => (classTag[String], Option[String]("")))
}
object Gen extends LowPriorityGen {
implicit val zero: Aux[0, TC[Int]] = instance(_ => (classTag[Int], Option[Int](0)))
}
def gen[X <: Int with Singleton](x: X)(implicit g: Gen[X]): g.Out = g(x)
gen(0) //(Int,Some(0))
gen(1) //(java.lang.String,Some())
原因与ClassTag
和 Option
有不同的方差。
尝试
type TC[T] = (ClassTag[_ <: T], Option[T])
def gen(x: Int): TC[_] = x match {
case 0 => (classTag[Int], Option[Int](0))
case _ => (classTag[String], Option[String](""))
}
即使您无法在类型中编码所需的 属性,您仍然可以在编译时使用模式匹配右侧的 check
检查它。
def gen(x: Int): (ClassTag[_], Option[_]) = x match {
case 0 => check(classTag[Int], Option[Int](0))
case _ => check(classTag[String], Option[String](""))
}
def check[T](classTag: ClassTag[T], option: Option[T]): (ClassTag[T], Option[T]) = (classTag, option)
事实证明,因为 Tuple4
类型参数是协变的:Tuple4[+T1, +T2, +T3, +T4]
,它不能很好地与不变类型 class 一起使用,例如 ClassTag
.
我创建了一个采用不变类型参数的包装器 class:
case class TC[T](ct: ClassTag[T], o: Option[T])
def gen(x: Int): TC[_] = x match {
case 0 => TC(classTag[Int], Option[Int](0))
case _ => TC(classTag[String], Option[String](""))
}
瞧,它起作用了。