#27 Что такое иммутабельность неизменяемость строк? Ответ на вопрос собеседования C# / .Net
Vložit
- čas přidán 6. 09. 2024
- #strings #immutablestrings #stringbuilder #csharp #dotnet #строки #andriyshyrokoriadov
В видео описаное что такое иммутабельность неизменяемость строк. Помимо неизменяемости строк дано описание:
- каким типом является строка - ссылочным или значимым
- что такое String Builder
- сравнение конкатенации строк со String Builder
Обзор представлен в форме ответа на вопрос, который встречается на собеседованиях на позицию "программист C# / .Net".
Подписывайтесь на канал [программирование, путешествия]: / @andreyshyrokoriadov
0:05 - введение
0:30 - каким типом является строка - ссылочным или значимым
3:47 - что такое иммутабельность неизменяемость строк
6:45 - класс String Builder
8:00 - сравнение производительности конкатенации строк со String Builder
12:30 - внутренняя имплементация класса String Builder
Текст к фильму доступен по ссылке: ashyrokoriadov...
Дополнительная информация:
- строки - docs.microsoft...
- String Builder - docs.microsoft...
Я ещё не досмотрел видео, но уже пишу коммент, это супер круто, ты рассказываешь как это работает под капотом, то что я искал, спасибо за работу! Желаю продвижения каналу
Спасибо за комментарий!
7:27 это же строковые литералы, компилятор их соединит в одну строку на этапе копиляции. Tоже самое будет если мы их объявим как
const string s = "Hello";
const string s1 = " ";
const string s2 = "world";
Console.WriteLine(s + s1 + s2);
вызов Console.WriteLine будет транслирован как Console.WriteLine("Hello world");
Недавно задали вопрос про интернирование строк. Так и пришел к этому видео! Спасибо большое!
Неожиданная подача, но очень понятно. 👍
Боже, какое крутое видео) Благодарю за Вашу работу.
Спасибо за отличный контент!
Только недавно решал какую-то кату в кодварс где работал со строкой и каждый раз при изменении строки ее нужно было присваивать в переменную, хотя это ссылочный тип, не понимал почему! а тут такая инфа на вес золота! Спасибо, это топ!
Какой у тебя kyu?
Видео супер. Спасибо
хороший материал
Спасибо большое!
Спасибо!
Если в строковом типе данных мы инициализируем объект и присваиваем какое - то значение, а это значение уже есть у другого объекта, то место в памяти для второго объекта выделено не будет, так как оно уже есть и объект будет ссылаться на это же значение первого объекта. Это вроде называется интернированием. Поправьте, если ошибаюсь. Для других объектов класcа Object подобное тоже применимо? Или это только строк касается? После объявления оператора new() разве не выделяется отдельное место в памяти для объектов , даже если их данные будут полностью совпадать с данными других объектов?
Если создать две разные строковые переменные, но с одинаковыми значениями в куче, то в стеке у каждой будет хранится одна и та же ссылка на область в куче с этим значением. Но я так и не понял, при их сравнивании будут сравниваться ссылки в стеке или сами значения в куче? По логике же, при сравнивании ссылочных типов, сравниваются их ссылки в стеке.
А также возник еще один вопрос: если строковый тип работает так, как я описал его выше, то как в такой же ситуации работает StringBuilder? Если я создам две разные переменные типа StringBuilder с одним и тем же значением внутри, то эти переменные будут ссылаться на одну и ту же область памяти, как и обычный string, или это будут два независимых объекта типа SB?
При == или Equals две строки будут сравниваться по значению (это исключение для объекта типа string). При использовании object.ReferenceEquals как следует из названия метода сравниваться будут ссылки, но если вы просто определите две стринг переменные с одинаковым значением, то для второй будет использована уже существующая строка в string pool и ReferenceEquals вернёт true. Но если вы объявите str1 = "Hello" а str2 = "Hello1".Replace("1", "") например, то Replace вернёт новую строку и тогда ReferenceEquals вернёт false, т.к. ссылки будут разные уже
@@ArtsiomAuhustsinovich Интересно, этого я не знал, насчёт Replace. Спасибо
3:02 - "согласитесь, это вообще бред" - а джава-программисты с этим живут 😀
Спасибо!
Может я проглядел, но не нашел примера кода по ссылке, где сравниваются StringBuilder и со сложением строк.
Тогда я еще не давал примеров в своём репо... однако сам код простой и каждый его сможет повторить за 15 минут.
откуда информация, что размер стека в 64-битных системах 4Mb? Можно источник?
Конкретного источника нет, однако на форумах часто об этом пишут и спрашивают. Например, тут:
stackoverflow.com/questions/28656872/why-is-stack-size-in-c-sharp-exactly-1-mb
Вы слышали про интернирование строк? на 3 минуте вы говорите бред. (ReferenceEquals(string1, string2) вернет True)
на 6 минуте вы говорите уже противоположное
Я думаю, Вы не поняли, что я сказал. Рекомендую еще раз пересмотреть эту часть видео, только на этот раз внимательно и с пониманием.
А что касается кода, то да - тут я согласен:
var string1 = "SampleString";
var string2 = "SampleString";
Console.WriteLine(string1 == string2); // TRUE
Console.WriteLine(ReferenceEquals(string1, string2)); // TRUE
Подскажите, а разве в методе FillStringCollection() в цикле при заполнении List не происходит неявного создания множества переменных типа string?
Я немного поправлю Ваше предложение: "...в методе FillStringCollection() в цикле при заполнении List происходит ЯВНОЕ создание множества (100 000) переменных типа string". Здесь мы явно создаем каждую строку в линии 46. Однако при конкатенации ("+") создание строк происходит не явно и проблема состоит в том, что не все об этом знают при написании кода.
@@AndreyShyrokoriadov Тогда непонятно откуда такие разительные отличия в работе двух методов. В любом случае сначала происходит заполнение коллекции List 100 000 уникальных строк (100 000 переменных), которые создаются на куче и даже на их создание должно уходить значительное время.
То что при конкатенации неявно создаются новые переменные строкового типа и тем самым ещё нагружают память это понятно, но тут слишком огромная разница во времени.
Я не поленился и запустил код, который я показывал в видео, но прежде я добавил таймеры, чтобы понять сколько выполняется каждый кусочек кода. Я использовал класс Stopwatch из пространства имен System.Diagnostics.
Результаты следующие:
- метод FillStringCollection() = 00:00:00.0600504;
- метод ConcatStrings() = 00:03:18.6770528; 3 минуты!
- метод ConcatStringsWithStringBuilder() = 00:00:00.0085115;
Процессор Intel Core i7 6 генерации.
@@AndreyShyrokoriadov Мне кажется в методе FillStringCollection() в цикле заполнения коллекции List в выражении result.Add(Guid.NewGuid().ToString()) переменная типа string создаётся по слабой ссылке и поэтому после заполнения сборщик мусора её удаляет и поэтому ресурсы не нагружаются. Как вы думаете?
Можно попробовать для проверки сделать так:
static void FillStringCollection()
{
var result = new List();
for (int i = 0; i < 100000; i++)
{
@string = Guid.NewGuid().ToString();
result.Add(@string);
}
_strings = result;
}
Ошибка в названии, в слове "неизменяеиость"
Спасибо. Исправил.