了解Scala中的存在类型

时间:2015-08-24 17:06:54

标签: scala existential-type

考虑以下代码

import scala.collection.mutable.Set
import scala.collection.mutable.HashMap

// classes to create field types that do conversion of string to other types

trait Field[A] {
    def convert(x: String): A // Need to define convert for the trait, too.
}

case class IntField extends Field[Int] {
    override def convert(x: String): Int = x.toInt
}

case class StringField extends Field[String] {
    override def convert(x: String): String = x
}

// this function can take any Field type and return a HashMap, 
// more important here is type of key not the value of HashMap
// which has to match with value returned from Field.convert()

def someFunc[A](field: Field[A]): HashMap[A, Int] = {
    val index = new HashMap[A, Int]()
    val data = List("111", "222", "333")

    for (line <- data) {
        val values: A = field.convert(line)
        index.put(values, 0)
    }
    index
}

// this empty set will be populated with Field objects, and here I get an error
var fields = Set[Field[A]]()

def addField[A](field: Field[A]): Unit = fields += field

addField(StringField())
addField(IntField())

for (field <- fields) println(someFunc(field))

// RESULT
Map(333 -> 0, 222 -> 0, 111 -> 0) // HashMap[String, Int]
Map(111 -> 0, 333 -> 0, 222 -> 0) // HashMap[Int, Int]

上面不会编译,创建not found: type A时错误为var fields - 。现在,当我将此行更改为:

var fields = Set[Field[A] forSome {type A}]()

一切都在编译,但我并不完全理解这里发生的事情。我理解,当执行var fields = Set[Field[A]]()类型A不存在但其他行如何解决此问题时,它是否是正确的解决方案,或者恰好在这种情况下工作?

2 个答案:

答案 0 :(得分:0)

Field[A] forSome {type A} - 您可以使用A作为类型(带有类型A的参数化字段),因为您在大括号中声明此类型,存在类型是一种表示您可以接受任何类型的方式,在您的情况下方法addField是参数化,使用具有存在类型的Seq [Field]是一个解决方案,因为这个集合将存储不同的类型。

答案 1 :(得分:0)

您的问题可能不是真实的存在类型,而是通用类型的定义和用法,因为var fields = A也不会编译。

var fields = Set[Field[A]]()

A未定义,因为您尚未在范围内的任何位置声明它。

trait Field[A] {

def someFunc[A](field: Field[A]): HashMap[A, Int] = {

def addField[A](field: Field[A]): Unit = fields += field

A被声明为类型参数,即它将由用法定义。

当您将StringFieldIntField放在fields var中时,我想您希望字段为任意类型的Set Field。所以通常你通过通配符告诉编译器:

var fields = Set[Field[_]]()

这基本上是写作的简短方法

var fields = Set[Field[A] forSome {type A}]()