Я задал довольно много вопросов о типах коллекции Scala и о том, как они могут быть использованы. Рассмотрим, как я мог бы написать некоторые службы API/реализация в Java:Дизайн Scala API; служба, возвращающая набор <I>, где я - некоторый интерфейс (аннотация/черта)
public interface JavaProductAPI {
public Set<IProduct> getProducts(String isin);
}
и теперь осущ:
public class JavaProductAPIImpl implements JavaProductAPI {
private Map<String, Set<ProductImpl>> productsByIsin;
public Set<IProduct> getProducts() {
Set<ProductImpl> s = productsByIsin.get(isin);
return s == null
? Collections.<IProduct>emptySet()
: Collections.<IProduct>unmodifiableSet(s);
}
}
позволяет сказать, что есть очень хорошая причина, почему мне нужно иметь доступ в рамках реализации услуг к набору продуктов как ProductImpl
s, а не IProduct
s.
Похоже, что в Scala нет реального способа достижения этой цели, в то же время эксплицитно возвращая scala.collection.immutable.Set
из метода доступа API. Если я не возражаю, возвращая копию набора.
я буду считать, что возвращение фактической копии данных плохая практика (не стесняйтесь спорить об этом!):
val productsByIsin: Map[String, scala.collection.Set[ProductImpl]] = ...
def getProducts(isin: String): scala.collection.immutable.Set[IProduct] = {
productsByIsin.get(isin) match {
case Some(s) => scala.collection.immutable.Set(s toSeq :_*)
case None => scala.collection.immutable.Set.empty
}
}
Так что поэтому мой единственный выбор реальный дизайн должен иметь API возвращает scala.collection.Set
и использовать только для чтения вида:
val productsByIsin: Map[String, scala.collection.mutable.Set[ProductImpl]] = ...
def getProducts(isin: String): scala.collection.Set[IProduct] = {
productsByIsin.get(isin) match {
case Some(s) => s readOnly
case None => scala.collection.Set.empty
}
}
Но это бессмысленный актерский состав, не так ли? Это то, что дало бы мне безответное предупреждение в Java, не так ли? Является ли scala-компилятор проверкой безопасности типа? –
Нет, компилятор Scala не проверяет безопасность приводов. В этом случае это безопасно. Чтобы убедиться в его безопасности, вы можете сделать следующее: productsByIsin.getOrElse (isin, immutable.Set.empty) .map (x => x: IProduct) , который проверяется компилятором, но он также создает новый карта. –
На самом деле 'Set' в Scala инвариантны только потому, что 'Set [A]' также является '(A => Boolean)', а правила дисперсии для наследования функций точно противоположны правилам для 'List'. Вот почему вы можете взять «list: List [ProductImpl]» и назначить его «val products»: List [IProduct] = list' без приведения в действие, и хотя вы не можете сделать то же самое с инвариантом 'Set' s, это абсолютно безопасно бросать его в суперкласс - неизменяемые Наборы не могут быть повреждены таким образом. Альтернативным и более элегантным способом было бы использовать 'Set [ProductImpl](). ToSet [IProduct]', но он создаст новую коллекцию. – Sergey