Комментарии 19
А эта фича связана только с числовыми индеками массивов, или она более общая, типа обобщения двух итераторов в произвольной коллекции, как это попытались сделать в С++?
А ведь можно двигаться еще дальше и получить "генераторы списков"...
В шарпе не итераторы а энумераторы, они похожи но семантически разные. Энумераторы не представляют собой позицию в контейнере, они могут только выдавать текущий элемент и смещаться на следующий.
По контракту энумератор не должен уметь сравнивать себя с другим энумератором той же коллекции, так что фича про числовые индексы, большего и не надо.
А генераторы списков в шарпе с самого начала есть, даже yield return
для их удобного написания завезли.
Очень похоже на срезы в питоне, только нет возможности указания шага
Меньше нагрузка на память.
Почитал документацию - range на массивы создаёт копию массива в нужном срезе, т.е. я не понял, почему нагрузка на память меньше. Тут ведь всё ещё хуже - новый синтаксис скрывает аллокации потенциально больших данных. Согласно той же документации, копирования нет только на Span и Memory. Т.е. нужно обращать внимание на тип коллекции, чтобы понять, будет выделение памяти или нет. И со Span'ом тоже спорный вопрос. Допустим, у меня есть массив в мегабайт, далее я создал range на 3 элемента и собираюсь пользоваться только им - не получится ли так, что в памяти будет болтаться 1 мегабайт бесхозной памяти, потому что Span удерживает ссылку на массив в целом?
Да, нагрузка на память в Решении 5 ровно такая же, как в Решении 1. Под капотом вызывается RuntimeHelpers.GetSubArray
, который создаёт новый массив.
есть массив в мегабайт, далее я создал range на 3 элемента и собираюсь пользоваться только им - не получится ли так, что в памяти будет болтаться 1 мегабайт бесхозной памяти, потому что Span удерживает ссылку на массив в целом
Так и получится. Чудес нет - либо выделяем новый массив из 3 элементов, и старый будет удалён сборщиком мусора, либо делаем AsMemory
/ AsSpan
- очень быстро и не выделяет память, но удерживает большой массив.
Вообще в подобной статье было бы здорово упомянуть AsMemory
& AsSpan
, они тоже работают с Range
:
var numbers = new int[] { 5, 1, 4, 2, 3, 7 };
Memory<int> result = numbers.AsMemory()[2..5];
Так и получится. Чудес нет
Согласен. Но в данной статье (и других похожих) делается вывод, что ranges являются (помимо прочего) решением проблем с памятью. Хотя по факту это просто синтаксический сахар, и ситуация мало поменялась, только добавилось новых подводных камней :) Я на это хотел обратить внимание.
"Вызовы ToList
, ToArray
проходятся по коллекции и выделяют новую память. "
Уже нет , мы это оптимизировали , теперь мы работает с абстракциями объектов в памяти , тут выделяется память только на алокацию типа (копейка), а потом мы присваеваем ссылку на объект.
(понятное дело эта оптимизация работает до первого изменения)
А поделитесь пожалуйста ссылкой на пруфы. Не вижу подобного ни в RangeIterator, ни в EnumerableHelpers, ни в Enumerable.ToList
не там смотрите , CLR
Так репозиторий по ссылке и есть runtime. Поделитесь своей ссылкой, если не трудно?
Можно ошибиться при передаче параметров в методы
Skip
иTake
(относится к начинающим программистам).
Где тут можно ошибиться когда методы так и называются "пропустить" и "взять", и передать только целоцисленное значение
https://referencesource.microsoft.com/#system.core/system/linq/Enumerable.cs,591
public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count) {
if (source == null) throw Error.ArgumentNull("source");
return TakeIterator<TSource>(source, count);
}
Имхо половина аргументов в статье высосона из пальца
Вы не работали с начинающими программистами
referencesource.microsoft.com - .net framework
source.dot.net - актуальный .NET (тоже самое что в гитхабе, но более удобный просмотр, как в referencesource)
Начиная с C# 9, с Range можно сделать вот такую штуку
Skip() Take() гораздо лучше читаются, чем эти браинфаки
Диапазоны (Ranges) в C# 8