【问题标题】:Scala - return a typeScala - 返回一个类型
【发布时间】:2012-11-28 03:23:49
【问题描述】:

我想从函数中返回一个类型。例如:

class Super
case class One(a: Int) extends Super
case class Two(b: Float) extends Super
case class Unknown extends Super

def decide(criterion: String): ??? = {
  criterion match {
    case "one" => One
    case "two" => Two
    case _ => Unknown
  }
}

所以我想返回类型本身,将其存储在 Map 中,以便以后在某处应用它:

val test = Buffer(
  ("ahaha" -> "one")
  ("ohoho" -> "two")
  ("lalala" -> "one")
)

var map = scala.collection.mutable.Map[String, Super]()

test.map {pair =>
  map(pair._1) = decide(pair._2)
}

这样以后我会喜欢:

def act(code: String) {
  map(code) match {
    case One => doSmth[One]()
    case Two => doSmth[Two]()
    case _ => doNothing()
  }
}

我知道有些部分,例如案例类的未使用参数,在这里可能看起来很奇怪,但在我工作的环境中就是这样,这个例子很完整,因为我不确定它是否会如果我拿走东西会有所不同...

那么我怎样才能让decide 函数返回一个类型,然后以类似于我所展示的方式使用它?

【问题讨论】:

  • 你可能会得到带有classOf(例如classOf[One])方法的java.lang.Class,所以函数的返回类型将是java.lang.Class[Super]
  • @om-nom-nom 工作了一半。我仍然无法将返回的类型作为类型参数传递给doSmth 方法...
  • 这与决定返回什么的问题没有真正的关系,但为什么在这里使用地图?为什么不直接传递函数decide

标签: scala types type-systems


【解决方案1】:

我认为您可能想要case object One 等,而不是使用Class 或ClassTag。然后你会得到有用的匹配支持。对于 act 方法,您的案例对象可以返回 ClassTag 或类似的,或者只是让 act 将 One 与 doSmth[OneClass] 等相关联。

看来您可以将您的案例伴侣变成案例对象。是不是很特别。

package typeswitch
import reflect.runtime.universe._

sealed trait Selection

class Super
case class One(a: Int) extends Super
case object One extends Selection
case class Two(b: Float) extends Super
case object Two extends Selection
case class Unknown() extends Super
case object Unknown extends Selection

object Test extends App {
  type What = Selection

  def decide(criterion: String): What = criterion match {
    case "one" => One
    case "two" => Two
    case _ => Unknown
  }

  val test = List(
    "ahaha" -> "one",
    "ohoho" -> "two",
    "lalala" -> "one"
  )

  val m = scala.collection.mutable.Map[String, What]()

  test map (pair => m(pair._1) = decide(pair._2))

  def act(code: String) = m(code) match {
    case One => doSmth[One]()
    // non-exhaustive
    //case Two => doSmth[Two]()
    case Unknown => doNothing()
    // handle exhaustively
    case s: Selection => doSmthNew(s)
  }
  def doSmthElse[A <: Super]()(implicit t: TypeTag[A]): A = {
    Console println s"Do st with $t"
    val claas: Class[_] = t.mirror.runtimeClass(t.tpe)
    null.asInstanceOf[A]
  }
  def doSmth[A <: Super]()(implicit t: ClassTag[A]): A = {
    Console println s"Do st with $t"
    val claas: Class[_] = t.runtimeClass
    null.asInstanceOf[A]
  }
  def doSmthNew[A >: What : ClassTag, B <: Super](what: A): B = {
    Console println s"Do st new with $what"
    null.asInstanceOf[B]
  }
  def doNothing() { }

  val res = act("lalala")
  Console println s"Got $res?"
}

【讨论】:

  • 好吧,一个不错的尝试,我在想类似的东西.. 但实际上,这是一个后备 - 解决方案假设没有直接使用类型本身 - 它使用伴随对象,在这种情况下, 与使用命名整数常量没有太大区别。但是,我想不出更好的东西了......也许 JVM 不会让我们做我需要的......
  • 您要查找的词是“nifty”。它没有命名为常量,因为您可以对匹配进行详尽的检查,并且很容易通过反射获得伴随类。你没有在 doSmth 中显示你想做什么。
  • @noncom 我认为您可能是对的。从您之前的评论中,我猜您不知道您应该使用 TypeTag 做什么?您可以从 TypeTag 或 ClassTag 取回您的类;我会编辑。此外, Selection[A <: super>
  • 谢谢!原来 TypeTag 是 Manifest 的替代品。我从来不是那里的专业人士,但我在阅读了你的帖子后研究了这个话题!确实一切都很好)
【解决方案2】:

对不起,如果这太基本了,但是:

$ scala
Welcome to Scala version 2.10.0-RC2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_06).
Type in expressions to have them evaluated.
Type :help for more information.

scala> trait Bar
defined trait Bar

scala> case class Foo(i:Int) extends Bar
defined class Foo

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> def f[A <: Bar : TypeTag]() = println(s" Do ${ implicitly[TypeTag[A]] }") 
f: [A <: Bar]()(implicit evidence$1: reflect.runtime.universe.TypeTag[A])Unit

scala> f[Foo]
 Do TypeTag[Foo]

【讨论】:

    猜你喜欢
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多