繁体   English   中英

Scala类型标签和类型别名

[英]scala type tags and type aliases

如果我在类中有类型别名定义,我可以在运行时将其与静态已知的类型或其他类型别名进行比较吗? 考虑:

type ConsArguments = (Option[Long], String, Option[String], Iterable[Input])
trait Type {
    val name :String
    type Value
    def apply(id :Option[Long], name :String, label :Option[String], inputs :Iterable[Input]=Iterable()) :Statistic
}
class BaseType[V :TypeTag](val name :String, constructor :((ConsArguments)) => Statistic {type Value=V}) extends Type{
    type Value = V
    def apply(id :Option[Long], name :String, label :Option[String], inputs :Iterable[Input]=Iterable()) :Statistic{type Value=V} =
        constructor((id, name, label, SortedSet[Input]()(Input.nameOrdering)++inputs))
}
val LongValued = new BaseType[Long]("long", (LongStatistic.apply _).tupled)
val lv :Type = LongValued
println("type of LongValued: "+universe.typeOf[LongValued.Value]+" is Long? "+(universe.typeOf[LongValued.Value]=:=universe.typeOf[Long]))
println("type of lv: "+universe.typeOf[lv.Value]+" is Long? "+(universe.typeOf[lv.Value]=:=universe.typeOf[Long]))

第一个比较为true,第二个为false。 我能以某种方式解决它吗? 通常,我将有更多的“类型”实例充当域模型中类的构造函数,并希望遍历这些类型的集合并选择一个匹配的集合。

问题是,当您静态键入lv作为Type您将丢弃有关Value类型成员的(静态)信息。 如果您要推断类型(或在显式类型注释中添加{ type Value = Long } ),就可以了。

但是,一旦您为Value使用不同值的Type实例集合进行了收集,您就会再一次走运,因为该集合的推断类型将类似于List[Type { type Value >: Long with Whatever }] ,基本上与List[Type]相同。 多亏了类型擦除(而且我并不是在讽刺,在这里,类型擦除确实是在做正确的事情),您将无法使用模式匹配或传统的Java反射工具从基于集合的项目中挑选项目。在其Value类型成员上。

因此,简短的答案是“不要这样做”。 您将进入一个静态类型无法帮助您的领域,几乎可以肯定有一种更好的方式来构建程序。 但是,如果您绝对坚持使用此方法,则可以使用类型标签。 下面是一个稍微简化的示例:

scala> import scala.reflect.runtime.universe.{ TypeTag, typeOf }
import scala.reflect.runtime.universe.{TypeTag, typeOf}

scala> trait Foo { type Value; implicit def vTag: TypeTag[Value] }
defined trait Foo

scala> class Bar[V](implicit val vTag: TypeTag[V]) extends Foo { type Value = V }
defined class Bar

scala> val xs = List(new Bar[Int], new Bar[String], new Bar[Symbol])
xs: List[Bar[_ >: Symbol with String with Int]] = ...

scala> xs.filter(_.vTag.tpe =:= typeOf[Symbol])
res0: List[Bar[_ >: Symbol with String with Int]] = List(Bar@68e2cd6f)

但是,这确实令人不快-我们只是传递有关值类型的信息作为运行时值本身。 新的反射API在语法上使此操作相当简洁,但这并不意味着它是一个好主意。

好的,我知道了。 更改非常简单:

type ConsArguments = (Option[Long], String, Option[String], Iterable[Input])
trait Type {
    val name :String
    type Value
    val tpe :universe.Type
    def apply(id :Option[Long], name :String, label :Option[String], inputs :Iterable[Input]=Iterable()) :Statistic
}
class BaseType[V :TypeTag](val name :String, constructor :((ConsArguments)) => Statistic {type Value=V}) extends Type{
    type Value = V
    val tpe = typeOf[V]
    def apply(id :Option[Long], name :String, label :Option[String], inputs :Iterable[Input]=Iterable()) :Statistic{type Value=V} =
        constructor((id, name, label, SortedSet[Input]()(Input.nameOrdering)++inputs))
}
val LongValued = new BaseType[Long]("long", (LongStatistic.apply _).tupled)
val lv :Type = LongValued
println("type of lv: "+lv.tpe+" is Long? "+(lv.tpe=:=universe.typeOf[Long]))

尽管如此,在整个代码中都使用double(类型...和val _:Type)声明还是有点令人讨厌。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM