Как на локальные переменные ссылаются в закрытиях? [дубликат]

Это поздний ответ на эту тему, но вот метод, который не использует временное хранилище:

public static class EnumerableExt
{
    public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> input, int blockSize)
    {
        var enumerator = input.GetEnumerator();

        while (enumerator.MoveNext())
        {
            yield return nextPartition(enumerator, blockSize);
        }
    }

    private static IEnumerable<T> nextPartition<T>(IEnumerator<T> enumerator, int blockSize)
    {
        do
        {
            yield return enumerator.Current;
        }
        while (--blockSize > 0 && enumerator.MoveNext());
    }
}

И некоторый тестовый код:

class Program
{
    static void Main(string[] args)
    {
        var someNumbers = Enumerable.Range(0, 10000);

        foreach (var block in someNumbers.Partition(100))
        {
            Console.WriteLine("\nStart of block.");

            foreach (int number in block)
            {
                Console.Write(number);
                Console.Write(" ");
            }
        }

        Console.WriteLine("\nDone.");
        Console.ReadLine();
    }
}
5
задан Anurag 21 May 2010 в 08:04
поделиться

5 ответов

Вы близко ...

Почему элемент имеет значение 'item3'? Разве цикл for не заканчивается, когда мне становится 3?

Да.

Если это закончится, элемент не должен оставаться 'item2'?

Нет. Этот пример немного сложен. Во время последней итерации цикла i равно 2, но он ссылается на 3-й элемент массива list , который равен 3. Другими словами, item == ' item '+ list [2] ==' item3 '

Или переменная item создается снова, когда testList вызывает функции?

Нет, в первый раз вы были почти правы. Я думаю, вы только что пропустили тот элемент [2] , который имеет значение 3.

4
ответ дан 13 December 2019 в 05:41
поделиться

Цикл заканчивается, когда i становится 3, но для переменной "item", хранящейся в замыкании и отображаемой предупреждением, устанавливается значение

var item = 'item' + list[i];

текст "item" + значение в списке [2]. Третий элемент списка - 3, поэтому текст - item3

0
ответ дан 13 December 2019 в 05:41
поделиться

Я думаю, что вам не хватает того, что list [i] недооценено, потому что i равно 3, а list определен только для 0 .. 2.

2
ответ дан 13 December 2019 в 05:41
поделиться

Переменная list хранится в закрытии, как вы говорите.

На самом деле вы можете получить доступ к переменной list , но вы пытаетесь получить доступ к list [3] . В конце концов, переменная i также сохраняется как закрытие, и ее значение равно 3, когда вызывается функция console.log .

2
ответ дан 13 December 2019 в 05:41
поделиться

Цикл for в buildList завершается до того, как вы сделаете следующее:

for (var j = 0; j < fnlist.length; j++) {
  fnlist[j]();
}

... следовательно, к тому времени (когда вы вызываете каждую функцию) переменная item будет тем, что было присвоено ему последним (т.е. "item3"), а i будет 3 (в результате последней операции i ++ ), и список [3] равен undefined .

Это все связано с тем, что цикл завершается до того, как вы вызываете функцию closure'd . Чтобы предотвратить это, вы можете создать новое закрытие, например:

function buildList(list) {
  var result = [];
  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push(
        (function(item, i){
            // Now we have our own "local" copies of `item` and `i`
            return function() {
                console.log(item + ' ' + list[i])
            };
        })(item, i)
    );
  }
  return result;
}
4
ответ дан 13 December 2019 в 05:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: