如何返回通配符泛型? [英] How to return wildcard generic?

查看:169
本文介绍了如何返回通配符泛型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带参数的类型别名,我想从一个方法返回不同参数类型的实例:

I have a type alias with parameter and I would like to return the instance of different parameter types from a method:

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](""))
}

这不起作用,并给我错误:

This does not work and gives me error:

错误:类型不匹配; 找到:(scala.reflect.ClassTag [_>:带字符串的整数],选项[任何]) 必需:TC [] (扩展为)(scala.reflect.ClassTag [ $ 1],选项[_ $ 1])forSome {type _ $ 1}

error: type mismatch; found : (scala.reflect.ClassTag[_ >: Int with String], Option[Any]) required: TC[] (which expands to) (scala.reflect.ClassTag[$1], Option[_$1]) forSome { type _$1 }

我尝试使用Any代替通配符_,但仍然无法正常工作:

And I tried to use Any instead of wildcard _, and it still does not work:

def gen(x: Int): TC[Any]

第2行:错误:类型不匹配; 找到的:scala.reflect.ClassTag [Int] 必需:scala.reflect.ClassTag [Any] 注意:Int< ;:任意,但特征ClassTag在T类型中是不变的. 您可能希望研究通配符类型,例如_ <: Any. (SLS 3.2.10) 大小写_ =>(classTag [String],Some(")) ^ 第3行:错误:类型不匹配; 找到的:scala.reflect.ClassTag [String] 必需:scala.reflect.ClassTag [Any] 注意:字符串< ;:任意,但特征ClassTag在T类型中是不变的. 您可能希望研究通配符类型,例如_ <: Any. (SLS 3.2.10)

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)

如何实现?

推荐答案

最好返回特定类型,而不是存在类型.如果要gen根据其参数返回不同的类型,则实际上gen是多态函数.使用类型类和单例类型尝试以下方法.

It's better to return specific type rather than existential. If you want gen to return different types depending on its argument then actually gen is a polymorphic function. Try the following approach with type class and singleton types.

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())


原因类似于中的原因.上一个问题. ClassTagOption的方差不同.


Reasons are similar to those in the previous question. ClassTag and Option have different variance.

尝试

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对其进行检查.


Even if you can't encode desirable property in types you still can check it at compile time with check in right hand side of pattern matching.

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)

这篇关于如何返回通配符泛型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆