Закрытие переменной цикла в Scala

Как обсуждалось в блоге Эрика ЛиппертаЗакрытие переменной цикла считается вредным, закрытие переменной цикла в C# может иметь неожиданные последствия. Я пытался понять, применима ли та же «подводная лоза» к Scala.

Прежде всего, поскольку это вопрос о Scala, я попытаюсь объяснить пример Эрика Липперта на C#, добавив несколько комментариев к его коду.

// Create a list of integers
var values = new List() { 100, 110, 120 };

// Create a mutable, empty list of functions that take no input and return an int
var funcs = new List>();

// For each integer in the list of integers we're trying
// to add a function to the list of functions
// that takes no input and returns that integer
// (actually that's not what we're doing and there's the gotcha).
foreach(var v in values)
  funcs.Add( ()=>v );

// Apply the functions in the list and print the returned integers.
foreach(var f in funcs)
  Console.WriteLine(f());

Большинство людей ожидают, что эта программа выведет 100, 110, 120. На самом деле она выводит 120 , 120, 120. Проблема в том, что функция () => v, которую мы добавляем в список funcs, закрывается по переменной v , а не по значению v . . Когда v изменяет значение, в первом цикле все три замыкания, которые мы добавляем в список funcs, «видят» одну и ту же переменную v, которая (к моменту их применения во втором цикле) имеет значение 120. для всех из них.

Я попытался перевести код примера на Scala:

import collection.mutable.Buffer
val values = List(100, 110, 120)
val funcs = Buffer[() => Int]()

for(v <- values) funcs += (() => v)
funcs foreach ( f => println(f()) )
// prints 100 110 120
// so Scala can close on the loop variable with no issue, or can it?

Действительно ли Scala не страдает от той же проблемы, или я просто плохо перевел код Эрика Липперта и не смог воспроизвести его?

Такое поведение сбило с толку многих доблестных разработчиков C#, поэтому я хотел убедиться, что со Scala не возникнет подобных странных ошибок. Но также, как только вы поймете, почему C# ведет себя так, как он ведет себя, вывод кода Эрика Липперта в качестве примера обретает смысл (по сути, это то, как работают замыкания): так что же Scala делает по-другому?

11
задан Peter Mortensen 30 May 2013 в 21:28
поделиться