2016-08-25 20 views
3

Я хочу, чтобы получить лучшее понимание того, что на самом деле происходит в этом коде при конвертировании из Java List к родовому Scala Seq:Scala: Возвращение изменяемый буфер из функции, которая возвращает Seq

import scala.collection.JavaConverters._ 

def foo(javaList: java.util.List[String]): Seq[String] = { 
    val scalaMutableBuffer: mutable.Buffer[String] = javaList.asScala 
    scalaMutableBuffer 
} 

... 

val bar = foo(someJavaList) 

Я правильно понимаю, что, хотя bar вводится как Seq[String], он использует изменяемый буфер на базовом уровне, потенциально влияя на производительность операций Seq? Является ли Seq просто ссылкой на буфер через ограничения Seq-признака или существует фактическое основное преобразование, которое продолжается? Было бы лучше подумать о значении bar содержит как изменчивое или неизменяемое?

Простите, насколько открытым этот вопрос, но я не чувствую, что у меня есть хорошее представление о том, что происходит, и я бы хотел изменить это. Например, были ли бы случаи, когда было бы предпочтительнее для меня преобразовать scalaMutableBuffertoList перед возвратом с foo?

Спасибо!

ответ

4

в то время как бар набирается как послед [String], он использует изменяемый буфер на лежащий в основе уровня

Вы правы, во время выполнения значение bar является mutable.ArrayBuffer[String] (как Buffer - это черта), а так как Seq[+A] - это черта, вы, как вызывающий, можете видеть только «секвенсивные» части ArrayBuffer, хотя вы всегда можете отдать его в буфер через buffer.asInstanceOf[mutable.ArrayBuffer[String]], а затем увидеть фактические «внутренние элементы», буфера.

потенциально влияющих на производительность операций Seq

Когда один выставляет Seq[A], вы обнажая «контракт», что базовая коллекция придерживается. Во время выполнения это всегда будет конкретная реализация. то есть, когда мы создаем Seq через apply:

scala> Seq(1,2,3) 
res0: Seq[Int] = List(1, 2, 3) 

Конкретное фактически List[Int].

Было бы лучше подумать, что панель значений содержит как изменчивую или неизменяемость?

Основополагающая реализация изменчива, но подвергается постоянному контракту. Это означает, что когда вы работаете в буфере с помощью абстракции черты Seq, в качестве вызывающего абонента нет доступных для вас операций.

Например, когда мы делаем:

scala> val bufferAsSeq: Seq[Int] = scala.collection.mutable.Buffer(1,2,3) 
bufferAsSeq: Seq[Int] = ArrayBuffer(1, 2, 3) 

scala> bufferAsSeq += 4 
<console>:12: error: value += is not a member of Seq[Int] 
     bufferAsSeq += 4 

Абстракции охраняет нас от позволяя пользователям вызывать операции мы не хотим их сделать по типу времени выполнения.

Например, будет ли какие-либо случаи, в которых было бы предпочтительнее для меня, чтобы преобразовать scalaMutableBuffer ToList перед возвращением из обув

Я думаю, что это в первую очередь мнение, основанное. Если вы не ощущаете черту Seq, вы всегда можете быть неизменным. Но помните, что для того, чтобы кто-то переделал копию Seq, он должен проверить тип времени выполнения и явно бросил на него, и когда вы делаете все ставки, вы отключены.

+0

Имеет смысл, спасибо за ответ! У меня есть реакция кишки против изменчивости в Scala, но реалистично неизменность - это абстракция поверх множества подходов к JVM-модификации - и похоже, что Seq обеспечивает эту абстракцию неизменности даже в этом случае. – Nathan

+0

@Nathan Я понимаю ваше чувство кишки. Когда вы работаете с Scala, вы хотите стремиться к неизменности на всем пути. Но опять же, нужно было бы усердно работать над абстракцией «Seq» в вашем случае и фактически использовать изменчивость изменчивой коллекции. –

+0

Из любопытства, если я назвал 'bar.asInstanceOf [scala.collection.mutable.Buffer [String]]', будет ли он делать общее преобразование из Seq в изменяемый буфер с использованием интерфейса Seq или будет пытаться с использованием базового двоичного представления? – Nathan