2015-08-24 3 views
0

Учитывая следующий кодПонимание экзистенциальные типы в Scala

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 не существует, но как другая строка исправляет эту проблему и является ли она правильным решением или просто работает в этом случае?

ответ

0

Field[A] forSome {type A} - вы можете использовать A как тип (параметризовать поле с типом A), потому что вы объявляете этот тип в фигурных скобках, экзистенциальные типы - это способ сказать, что вы можете принять любой тип в вашем случае, когда метод addField parametrize, используя Seq [Field] с экзистенциальным типом, является одним из решений, потому что эта коллекция будет хранить разные типы.

+0

Если я просто объявить 'типа Ā' в верхней части коды и использовать' вар fields = Set [Field [A]]() 'он все равно не будет компилироваться. Это потому, что 'Поле [A] forSome {type A}' создает 'тип A' в контексте' Field [A] '? Если это имеет смысл. –

+0

Если вы объявляете такой тип: type A = Field [B] forSome {type B}, он будет скомпилирован, поэтому A forSome {type A} - это просто специальная конструкция scala, которая позволяет создавать экзистенциальные типы, которые являются способом сказать что это может быть любой тип – grotrianster

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 объявлен как параметр типа, то есть он будет определяться использованием.

Как вы положили оба StringField и IntField в вашем fields вар, я предполагаю, что вы хотите поля быть Set любого рода Field. Так обычно компилятор, что с помощью шаблона:

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

, который по существу короткого способ написания

var fields = Set[Field[A] forSome {type A}]() 
Смежные вопросы