Полезны ли слайсы


польза и вред для человеческого организма.

В настоящее время люди все чаще придерживается здорового образа жизни. Стало популярным заниматься спортом, фитнесом и правильно питаться. На такой образ жизни с каждым годом "подсаживаются" все больше людей, которые стараются привести тело и организм в порядок. Слайсы вошли в рацион многих ЗОЖников. Такой продукт можно найти на полках магазинов со здоровым питанием. Что такое слайсы? Пользу и вред этого продукта мы и рассмотрим в данной статье.

Хлеб нового поколения - слайсы

Слово "слайс" с английского переводиться как слой, кусочек или ломтик. В нашем случае слайсами называют сухие хлебцы из злаков. Это новый продукт, который появился на полках магазинов не так давно. Технология производства слайсов заключается в нагревании зерен до их взрывания. Как и попкорн, который мы получаем путем нагревания. Предоставленный продукт является диетическим и пользуется огромным спросом у людей, которые следят за своим весом. Однако изучены ли польза и вред слайсов? Попробуем в этом разобраться.

Химический состав слайсов

Ломтики готовятся из многих зерновых культур:

  • овес;
  • кукуруза;
  • гречиха;
  • рожь;
  • пшеница.

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

В составе слайсов много полезных микроэлементов и витаминов. В химический состав на 100 г продукта входят:

  • углеводы - 60,5 г;
  • жиры -2,6 г;
  • белки - 14 г;
  • пищевые волокна - 2,4 г;
  • витамины В1, В2, В4, В5, В6, В9;
  • витамин Е - 0,55 мг;
  • витамин К - 7,8 мкг;
  • витамин РР - 4,714 мг;
  • микроэлементы;
  • макроэлементы;
  • аминокислоты и усвояемые углеводы.

Плюсы и минусы

О пользе и вреде слайсов информации не так уж и много. Чаще об этом продукте отзываются с положительной стороны. Но это еще не до конца изученная тема. Ведь опыты, которые провели недавно на крысах, показатели неутешительный результат. Питаясь экструдированными продуктами, животные умирали. Ниже рассмотрим пользу и вред слайсов на основе их составляющих.

Плюсы:

  • улучшается работа пищеварительного тракта;
  • снижается риск появления сердечно-сосудистых заболеваний;
  • производится очистка организма от токсинов, холестерина и тяжелых металлов;
  • улучшается кожный покров;
  • в норму приходит работа почек и печени;
  • проходит дисбактериоз кишечника.

К минусам в вопросе о пользе и вреде слайсов можно отнести только ограничение в потреблении и возрастные рамки.

Слайсы "Пшеничные"

Из всего ассортиментного ряда продуктов самыми покупаемыми являются слайсы из пшеницы. По составу и калорийности один кусочек пшеничного хлеба можно приравнять к четырем хлебцам. Польза пшеничных слайсов (вреда от них нет никакого), помимо вышеописанного списка, состоит в еще нескольких пунктах.

  1. Слайсы из пшеницы приводят в нормальный ритм нервную систему.
  2. Обогащают организм нужными ему элементами.

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

Ломтики из пшеницы содержат большое количество калия и магния, что улучшает работу кишечника. Чтобы привыкнуть к вкусовым качествам слайсов, можно для начала заменять часть хлеба пшеничными ломтиками. Ведь по вкусу слайсы нравятся не всем, но постепенное введение в рацион исправит эту ситуацию.

Слайсы с несколькими злаками

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

  1. Пшеница и рис. Отличное сочетание для нервной системы. Стабилизируют сон и повышают общий жизненный тонус.
  2. Пшеница с кукурузой. Рекомендуются к употреблению людям, которые хотят вывести токсины и шлаки из организма.
  3. Пшеница с гречкой. Снижают аппетит и способствуют уменьшению веса.
  4. Пшеница с овсом. Улучшают состояние кожи, волос и ногтей.
  5. Пшеница с ячменем. Способствуют хорошей работе кишечника и снижению веса.

Что показал опрос среди покупателей о вреде и пользе слайсов? Отзывы в основном положительные. Главное преимущество данного продукта в том, что он имеет полезный состав и способствует выведению вредных веществ из организма.

Преимущества слайсов

Ломтики из злаков - универсальны. Их можно сочетать со многими продуктами, а также применять в виде самостоятельного перекуса. Слайс порой заменяют хлеб и становятся основой для бутерброда. Либо ломтики можно поломать на кусочки и залить молоком или йогуртом - это будет прекрасным завтракам. Злаковые ломтики имеют огромное преимущество перед хлебом, так как это продукт, который:

  • приготовлен без муки и дрожжей;
  • не имеет вредных жиров;
  • диетический;
  • приемлем в постные дни;
  • может заменить перекус;
  • не имеет консервантов;
  • натуральный и экологически чистый;
  • богатый клетчаткой и другими полезными микроэлементами;
  • быстро насыщает организм и снижает чувство голода.

Если в Сети почитать отзывы врачей о пользе и вреде пшеничных слайсов, то можно заметить одну закономерность. Все они сходятся в едином мнении, что слайсы - это диетический продукт. Он содержат оболочку семян и его зародыши, что помогает снизить холестерин в крови. Если употреблять этот продукт постоянно в пищу, то наладится углеводный обмен в организме, выведутся токсины и радионуклиды. А главное, клетчатка, которая входит в состав слайсов, помогает снизить вес.

ломтиков: главное | Справочный центр AppSheet

Когда вы показываете содержимое таблицы в своем приложении, вам не нужно отображать каждую строку, каждый столбец и каждое действие. Вместо этого вы можете «разрезать» данные, выбрав подмножество столбцов, действий и строк.

Что такое срез?

Срез - это подмножество строк, столбцов и действий в таблице. Определение среза состоит из пяти компонентов:

  1. Таблица, на которой оно основано (обязательно)
  2. Разрешает ли срез добавлять, удалять и обновлять? (обязательно)
  3. Подмножество строк, которое он сохраняет из таблицы (необязательно)
  4. Подмножество столбцов, которое он сохраняет из таблицы (необязательно)
  5. Подмножество действий, которое он сохраняет из таблицы (необязательно)

Это важно чтобы отметить, что срез не требует подмножества строк, столбцов и действий.Фактически, обычно подмножество только строк или только столбцов / действий в зависимости от ситуации.

Срезы наиболее полезны, когда вы хотите создать UX-представление части таблицы. Например, если у вас есть таблица со списком людей, у вас могут быть столбцы для их имени, фамилии, дня рождения, адреса и номера телефона. Однако, если вы хотите видеть в представлении только их имя и номер телефона, вы можете создать срез, который отфильтровывает все столбцы в таблице людей, кроме имени и номера телефона.

Помните, что после того, как вы определите срез, вам все равно нужно будет использовать его в представлении UX.

Ниже у нас есть вкладка «Срезы» в редакторе. Он находится в разделе «Данные». Вы можете добавить столько фрагментов, сколько вам нужно, с помощью кнопки «Добавить новый фрагмент».

После этого вы увидите эти параметры для создания нового среза.

Чтобы просмотреть, какие строки и / или столбцы данных содержит ваш фрагмент, нажмите кнопку «Просмотреть данные». Вы также можете назвать свой срез как-нибудь описательным и выбрать, из какой таблицы вы выбираете данные для среза.

Чтобы узнать больше о фильтрации строк, столбцов и действий, прочтите Условия фильтрации строки среза, Столбцы среза и Действия среза соответственно.

Вот пример завершенного фрагмента в приложении "Национальные парки", в котором используется выражение.

После того, как вы добавили срез, вы можете определить его более подробно и создать для него UX-представление.

Для получения дополнительной информации ознакомьтесь с этой демонстрацией на срезах:

Если вы хотите узнать больше о срезах и глубокой фильтрации данных, посмотрите этот веб-семинар:

Более богатые приложения могут использовать более одного фрагмента таблицы.

На вкладке «Данные»> «Срезы» нажмите «Новый фрагмент», чтобы добавить еще один фрагмент данных. Он автоматически добавляется в ваше приложение, когда вы сохраняете изменения.

Еще одно применение срезов - определение логического подмножества таблицы, которое затем можно использовать в других выражениях (например, в ограничении столбца Valid_If или в правиле рабочего процесса) .Для этого сценария использования срезы обычно используют фильтры строк, но не подмножества столбцов или действий.

.

Go Slices: использование и внутреннее устройство

Эндрю Герранд
5 января 2011 г.

Введение
Тип среза

Go обеспечивает удобные и эффективные средства работы с последовательности типизированных данных. Срезы аналогичны массивам в других языках, но обладают некоторыми необычными свойствами. В этой статье мы рассмотрим, что такое срезы и как они используются.

Массивы

Тип среза - это абстракция, построенная на основе типа массива Go, Итак, чтобы понять срезы, мы должны сначала понять массивы.

Определение типа массива указывает длину и тип элемента. Например, тип [4] int представляет собой массив из четырех целых чисел. Размер массива фиксированный; его длина является частью его типа ( [4] int и [5] int различны, несовместимые типы). Массивы можно индексировать обычным способом, поэтому выражение s [n] обращается к n-й элемент, начиная с нуля.

  var a [4] int а [0] = 1 я: = а [0] // я == 1  

Массивы не нужно инициализировать явно; нулевое значение массива - это готовый к использованию массив, элементы которого сами обнуляются:

  // a [2] == 0, нулевое значение типа int  

Представление в памяти [4] int - это всего четыре целых числа, расположенных последовательно:

Массивы

Go - это значения.Переменная массива обозначает весь массив; это не указатель на первый элемент массива (как в случае с C). Это означает, что когда вы присваиваете или передаете значение массива, вы делаете копия его содержания. (Чтобы избежать копирования, вы можете передать в массив указатель , но тогда это указатель на массив, а не на массив.) Один из способов подумать о массивы - это своего рода структура, но с индексированными, а не именованными полями: составное значение фиксированного размера.

Литерал массива можно указать так:

  b: = [2] строка {"Penn", "Teller"}  

Или вы можете попросить компилятор подсчитать элементы массива за вас:

  b: = [...] строка {"Penn", "Teller"}  

В обоих случаях тип b - [2] строка .

Ломтики

У массивов есть свое место, но они немного негибкие, поэтому вы не часто видите их в коде Go. А вот ломтики есть везде. Они построены на массивах, чтобы обеспечить большую мощность и удобство.

Спецификация типа для среза - [] T , где T - тип элементов среза. В отличие от типа массива, тип среза не имеет указанной длины.

Литерал среза объявляется так же, как литерал массива, за исключением того, что вы не учитываете количество элементов:

  букв: = [] строка {"a", "b", "c", "d"}  

Срез можно создать с помощью встроенной функции make с подписью

  func make ([] T, len, cap) [] T  

, где T обозначает тип элемента создаваемого среза. Функция make принимает тип, длину, и дополнительная емкость.При вызове make выделяет массив и возвращает срез, который ссылается на этот массив.

  var s [] байт s = make ([] байт, 5, 5) // s == [] байт {0, 0, 0, 0, 0}  

Если аргумент емкости опущен, по умолчанию используется указанная длина. Вот более сжатая версия того же кода:

  с: = make ([] байт, 5)  

Длину и емкость среза можно проверить с помощью встроенных функций len и cap .

  лин (с) == 5 cap (s) == 5  

В следующих двух разделах обсуждается взаимосвязь между длиной и емкостью.

Нулевое значение среза - ноль . Обе функции len и cap возвращают 0 для нулевого среза.

Срез также может быть сформирован путем «разрезания» существующего среза или массива. Нарезка выполняется путем указания полуоткрытого диапазона с двумя индексами, разделенными двоеточием. Например, выражение b [1: 4] создает срез, включающий элементы 1–3 из b (индексы результирующего среза будут от 0 до 2).

  b: = [] байт {'g', 'o', 'l', 'a', 'n', 'g'} // b [1: 4] == [] байт {'o', 'l', 'a'}, используя то же хранилище, что и b  

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

  // b [: 2] == [] байт {'g', 'o'} // b [2:] == [] байт {'l', 'a', 'n', 'g'} // b [:] == b 

 

Это также синтаксис для создания среза по массиву:

  x: = [3] строка {"Лайка", "Белка", "Стрелка"} s: = x [:] // срез, ссылающийся на хранилище x  
Устройство Slice

Срез - это дескриптор сегмента массива.Он состоит из указателя на массив, длины сегмента, и его емкость (максимальная длина сегмента).

Наша переменная s , созданная ранее командой make ([] byte, 5) , имеет такую ​​структуру:

Длина - это количество элементов, на которые ссылается срез. Емкость - это количество элементов в базовом массиве (начало в элементе, на который указывает указатель среза). Разница между длиной и вместимостью станет ясна по мере того, как мы идем. через следующие несколько примеров.

Когда мы нарезаем s , наблюдаем изменения в структуре данных среза и их отношение к базовому массиву:

  с = с [2: 4]  

Нарезка не копирует данные среза. Он создает новое значение среза, которое указывает на исходный массив. Это делает операции среза столь же эффективными, как и манипулирование индексами массива. Следовательно, изменение элементов (не самого среза) повторного среза изменяет элементы исходного среза:

  d: = [] байт {'r', 'o', 'a', 'd'} e: = d [2:] // e == [] байт {'a', 'd'} e [1] = 'м' // e == [] байт {'a', 'm'} // d == [] байт {'r', 'o', 'a', 'm'}  

Ранее мы нарезали s на длину короче, чем его вместимость.Мы можем увеличить s до его емкости, снова разрезав его:

  s = s [: крышка (и)]  

Срез не может быть увеличен сверх его емкости. Попытка сделать это вызовет панику во время выполнения, так же, как при индексировании за пределами среза или массива. Точно так же срезы нельзя повторно нарезать ниже нуля для доступа к более ранним элементам в массиве.

Растущие срезы (функции копирования и добавления)

Для увеличения емкости среза необходимо создать новый, больший фрагмент и скопируйте в него содержимое исходного фрагмента.Этот метод показывает, как реализации динамических массивов из других языков работать за кулисами. В следующем примере емкость с удваивается за счет создания нового среза, t , копирование содержимого s в t , а затем присвоение значения среза t до s :

  t: = make ([] byte, len (s), (cap (s) +1) * 2) // +1 в случае cap (s) == 0 for i: = range s { t [i] = s [i] } s = t  

Цикл этой общей операции упрощается за счет встроенной функции копирования.Как следует из названия, copy копирует данные из исходного слоя в целевой. Возвращает количество скопированных элементов.

  func copy (dst, src [] T) int  

Функция copy поддерживает копирование между срезами разной длины (копируется только до меньшего количества элементов). Кроме того, копия может обрабатывать исходные и целевые фрагменты, которые совместно используют тот же базовый массив, правильная обработка перекрывающихся срезов.

Используя copy , мы можем упростить приведенный выше фрагмент кода:

  t: = make ([] byte, len (s), (cap (s) +1) * 2) копия (т, с) s = t  

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

  func AppendByte (slice [] byte, data ... byte) [] byte { m: = len (срез) n: = m + len (данные) if n> cap (slice) {// при необходимости перераспределяем // выделяем вдвое больше, чем нужно, для будущего роста. newSlice: = make ([] байт, (n + 1) * 2) копия (новый срез, срез) slice = newSlice } slice = срез [0: n] копия (фрагмент [m: n], данные) вернуть кусок }  

Можно использовать AppendByte так:

  p: = [] байт {2, 3, 5} p = AppendByte (p, 7, 11, 13) // p == [] байт {2, 3, 5, 7, 11, 13}  

Функции, такие как AppendByte , полезны, поскольку предлагают полный контроль по пути выращивания ломтика.В зависимости от характеристик программы, может быть желательно выделить более мелкие или большие куски, или установить предел размера перераспределения.

Но большинству программ не нужен полный контроль, так что Go предоставляет встроенную функцию и добавление , которая подходит для большинства целей; имеет подпись

  func append (s [] T, x ... T) [] T  

Функция append добавляет элементы x в конец среза s , и увеличивает срез, если требуется большая емкость.

  a: = make ([] int, 1) // a == [] int {0} а = добавить (а, 1, 2, 3) // a == [] int {0, 1, 2, 3}  

Чтобы добавить один фрагмент к другому, используйте ... для расширения второго аргумента до списка аргументов.

  a: = [] строка {"Джон", "Пол"} b: = [] строка {"Джордж", "Ринго", "Пит"} a = append (a, b ...) // эквивалентно «append (a, b [0], b [1], b [2])» // a == [] строка {"Джон", "Пол", "Джордж", "Ринго", "Пит"}  

Поскольку нулевое значение среза ( nil ) действует как срез нулевой длины, вы можете объявить переменную среза, а затем добавить к ней в цикле:

  // Фильтр возвращает только новый срез // элементы s, удовлетворяющие fn () func Filter (s [] int, fn func (int) bool) [] int { var p [] int // == ноль for _, v: = range s { если fn (v) { p = добавить (p, v) } } вернуть p }  
Возможная "ошибка"

Как упоминалось ранее, повторная нарезка среза не создает копию базового массива.Полный массив будет храниться в памяти до тех пор, пока на него не исчезнут ссылки. Иногда это может привести к тому, что программа будет удерживать все данные в памяти, когда нужен только небольшой кусочек.

Например, эта функция FindDigits загружает файл в память и выполняет поиск это для первой группы последовательных числовых цифр, возвращая их как новый кусок.

  var digitRegexp = regexp.MustCompile ("[0-9] +") func FindDigits (строка имени файла) [] byte { b, _: = ioutil.ReadFile (имя файла) вернуть цифруRegexp.Find (b) }  

Этот код ведет себя как объявлено, но возвращенный байт [] указывает на массив, содержащий весь файл. Поскольку срез ссылается на исходный массив, пока срез хранится вокруг сборщика мусора, он не может освободить массив; несколько полезных байтов файла сохраняют все содержимое в памяти.

Чтобы решить эту проблему, можно скопировать интересные данные в новый срез, прежде чем возвращать его:

  func CopyDigits (строка имени файла) [] byte { b, _: = ioutil.ReadFile (имя файла) b = digitRegexp.Find (b) c: = make ([] байт, len (b)) копия (c, b) вернуть c }  

Более краткая версия этой функции может быть построена с использованием добавления . Это оставлено читателю в качестве упражнения.

Дополнительная литература

Effective Go содержит подробный обработка ломтиков и массивы, и спецификацию языка Go определяет

.

3 способа сравнения срезов (массивов) · YourBasic Go

yourbasic.org/golang

Базовый кейс

В большинстве случаев вам нужно написать собственный код для сравнения элементов двух срезов .

  // Equal указывает, содержат ли a и b одинаковые элементы. // Аргумент nil эквивалентен пустому фрагменту. func Equal (a, b [] int) bool { if len (a)! = len (b) { вернуть ложь } для i, v: = диапазон a { if v! = b [i] { вернуть ложь } } вернуть истину }  

Однако для массивов можно использовать операторы сравнения == и ! = .

  a: = [2] int {1, 2} b: = [2] int {1, 3} fmt.Println (a == b)  

Значения массива сопоставимы, если сопоставимы значения типа элемента массива. Два значения массива равны, если равны их соответствующие элементы. Спецификация языка программирования Go: операторы сравнения

Оптимизированный код для байтовых срезов

Для сравнения байтовых срезов используйте оптимизированные байтов. Равно . Эта функция также обрабатывает нулевые аргументы как эквивалент пустых фрагментов.

Универсальный код для рекурсивного сравнения

В целях тестирования вы можете использовать Reflect.DeepEqual . Он рекурсивно сравнивает два элемента любого типа.

  var a [] int = nil var b [] int = make ([] int, 0) fmt.Println (отразите.DeepEqual (a, b))  

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

Дополнительная литература

Срезы и массивы за 6 простых шагов

Поделиться:

.

Как использовать емкость и длину среза в Go

Быстрая всплывающая викторина - что выводит следующий код?

  vals: = make ([] int, 5) для i: = 0; я <5; i ++ { vals = добавить (vals, я) } fmt.Println (vals)  

Если вы угадали [0 0 0 0 0 0 1 2 3 4] , вы правы.

Подождите, что? Почему не [0 1 2 3 4] ?

Не волнуйтесь, если вы ошиблись с тестом. Это довольно частая ошибка при переходе на Go, и в этом посте мы расскажем, почему результат не соответствует вашим ожиданиям, а также как использовать нюансы Go, чтобы сделать ваш код более эффективным.

Срезы против массивов

В Go есть как массивы, так и срезы. Поначалу это может сбивать с толку, но как только вы привыкнете к этому, вам это понравится. Доверьтесь мне.

Между срезами и массивами есть много различий, но основное из них, на котором мы хотим сосредоточиться в этой статье, заключается в том, что размер массива является частью его типа, тогда как срезы могут иметь динамический размер, поскольку они являются оболочкой вокруг массивов.

Что это означает на практике? Что ж, допустим, у нас есть массив var a [10] int .Этот массив имеет фиксированный размер, и его нельзя изменить. Если бы мы вызывали len (a) , он всегда возвращал бы 10, потому что этот размер является частью типа. В результате, если вам внезапно понадобится более 10 элементов в вашем массиве, вам придется создать новый объект с совершенно другим типом, например var b [11] int , а затем скопировать все свои значения из в до b .

Хотя наличие массивов с заданными размерами полезно в определенных случаях, в целом разработчики этого не хотят.Вместо этого они хотят работать с чем-то похожим на массив в Go, но со способностью расти со временем. Один из грубых способов сделать это - создать массив, который намного больше, чем он должен быть, а затем рассматривать подмножество массива как свой массив. Пример этого показан в приведенном ниже коде.

  var vals [20] int для i: = 0; я <5; i ++ { vals [i] = i * i } subsetLen: = 5 fmt.Println ("Подмножество нашего массива имеет длину:", subsetLen) // Добавляем новый элемент в наш массив vals [subsetLen] = 123 subsetLen ++ fmt.Println ("Подмножество нашего массива имеет длину:", subsetLen)  

С помощью этого кода у нас есть массив с заданным размером 20, но поскольку мы используем только подмножество, наш код может притвориться, что длина массива равна 5, а затем 6 после добавления нового элемента в наш массив.

Так (очень грубо говоря) работают срезы. Они обертывают массив с заданным размером, так же как наш массив в предыдущем примере имеет заданный размер 20.

Они также отслеживают подмножество массива, доступного для использования вашей программой - это атрибут длины , который аналогичен переменной subsetLen в предыдущем примере.

Наконец, срез также имеет емкость , что аналогично общей длине нашего массива (20) в предыдущем примере. Это полезно, потому что показывает, насколько велико может вырасти ваше подмножество, прежде чем оно перестанет помещаться в массив, поддерживающий срез. Когда это действительно произойдет, потребуется выделить новый массив, но вся эта логика скрыта за функцией append .

Короче говоря, объединение срезов с функцией append дает нам тип, очень похожий на массивы, но способный со временем расти для обработки большего количества элементов.

Давайте снова посмотрим на предыдущий пример, но на этот раз мы будем использовать срез вместо массива.

  var vals [] int для i: = 0; я <5; i ++ { vals = добавить (vals, я) fmt.Println ("Длина нашего фрагмента:", len (vals)) fmt.Println ("Вместимость нашего среза:", cap (vals)) } // Добавляем новый элемент в наш массив vals = добавить (vals, 123) fmt.Println ("Длина нашего фрагмента:", len (vals)) fmt.Println ("Вместимость нашего среза:", cap (vals)) // Доступ к элементам такой же, как и к массиву fmt.Println (vals [5]) fmt.Println (vals [2])  

Мы по-прежнему можем обращаться к элементам в нашем срезе так же, как к массивам, но с помощью среза и функции append нам больше не нужно думать о размере резервного массива. Мы все еще можем понять эти вещи, используя функции len и cap , но нам не нужно слишком о них беспокоиться. Аккуратно, правда?

Вернуться к популярной викторине

Имея это в виду, давайте еще раз взглянем на код нашей всплывающей викторины, чтобы увидеть, что пошло не так.

  vals: = make ([] int, 5) для i: = 0; я <5; i ++ { vals = добавить (vals, я) } fmt.Println (vals)  

При вызове make нам разрешается передавать до 3 аргументов. Первый - это тип, который мы выделяем, второй - длина , типа, а третий - это , емкость типа (, этот параметр - необязательный, ).

Передавая аргументы make ([] int, 5) , мы сообщаем нашей программе, что хотим создать срез длиной 5, и для емкости по умолчанию задана предоставленная длина - в данном случае 5.

Хотя сначала это может показаться тем, что мы хотели, важное различие здесь заключается в том, что мы сказали нашему срезу, что мы хотим установить как для длины , так и для , и , на 5 , а затем мы приступили к вызову append , которая предполагает, что вы хотите добавить новый элемент после начальных 5, поэтому она увеличит емкость и начнет добавлять новые элементы в конце среза.

Фактически вы можете увидеть изменение емкости, если добавите в свой код оператор Println () .

  vals: = make ([] int, 5) fmt.Println ("Емкость была:", cap (vals)) для i: = 0; я <5; i ++ { vals = добавить (vals, я) fmt.Println ("Емкость сейчас:", cap (vals)) } fmt.Println (vals)  

В результате мы получаем результат [0 0 0 0 0 0 1 2 3 4] вместо желаемого [0 1 2 3 4] .

Как это исправить? Что ж, есть несколько способов сделать это, поэтому мы рассмотрим два из них, и вы можете выбрать тот, который наиболее подходит в вашей ситуации.

Запись непосредственно в индексы вместо использования добавления

Первое исправление - оставить вызов make без изменений и явно указать индекс, который вы хотите установить для каждого элемента. В результате мы получим следующий код:

  vals: = make ([] int, 5) для i: = 0; я <5; i ++ { vals [i] = i } fmt.Println (vals)  

В этом случае значение, которое мы устанавливаем, совпадает с индексом, который мы хотим использовать, но вы также можете отслеживать индекс независимо.

Например, если вы хотите получить ключи карты, вы можете использовать следующий код.

  пакет основной импорт "fmt" func main () { fmt.Println (keys (map [string] struct {} { "собака": struct {} {}, "кошка": struct {} {}, })) } func keys (m map [string] struct {}) [] string { ret: = make ([] строка, len (m)) я: = 0 for key: = range m { ret [i] = ключ я ++ } возвратиться }  

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

Это подводит нас ко второму подходу, который мы собираемся рассмотреть…

Используйте 0 в качестве длины и вместо этого укажите вашу вместимость

Вместо того, чтобы отслеживать, в какой индекс мы хотим добавить наши значения, мы можем вместо этого обновить наш вызов make и предоставить ему два аргумента после типа среза. Первая, длина нашего нового фрагмента, будет установлена ​​на 0 , поскольку мы не добавили никаких новых элементов в наш фрагмент.Второй, емкость нашего нового среза, будет установлен на длину параметра карты, потому что мы знаем, что в наш срез в конечном итоге будет добавлено столько строк.

При этом за кулисами будет построен тот же массив, что и в предыдущем примере, но теперь, когда мы вызываем append , он будет знать, что нужно разместить элементы в начале нашего среза, потому что длина среза равна 0.

  пакет основной импорт "fmt" func main () { fmt.Println (keys (map [string] struct {} { "собака": struct {} {}, "кошка": struct {} {}, })) } func keys (m map [string] struct {}) [] string { ret: = make ([] строка, 0, len (m)) for key: = range m { ret = добавить (ret, ключ) } возвратиться }  

Почему мы вообще беспокоимся о емкости, если append обрабатывает ее?

Следующее, что вы можете спросить: «Почему мы вообще сообщаем нашей программе емкость, если функция append может обрабатывать увеличение емкости моего фрагмента за меня?»

По правде говоря, в большинстве случаев вам не нужно слишком об этом беспокоиться.Если это значительно усложняет ваш код, просто инициализируйте свой срез с помощью var vals [] int и позвольте функции append выполнять тяжелую работу за вас.

Но этот случай другой. Это не тот случай, когда трудно объявить емкость; Фактически, на самом деле довольно легко определить, какой должна быть конечная емкость нашего фрагмента, потому что мы знаем, что он будет отображаться непосредственно на предоставленную карту. В результате мы можем объявить емкость нашего среза при его инициализации и избавить нашу программу от необходимости выполнять ненужное выделение памяти.

Если вы хотите увидеть, как выглядят дополнительные выделения памяти, запустите следующий код на Go Playground. Каждый раз, когда емкость увеличивается, нашей программе требовалось еще раз выделить память.

  пакет основной импорт "fmt" func main () { fmt.Println (keys (map [string] struct {} { "собака": struct {} {}, "кошка": struct {} {}, "мышь": struct {} {}, "волк": struct {} {}, "аллигатор": struct {} {}, })) } func keys (m map [string] struct {}) [] string { var ret [] строка fmt.Println (cap (ret)) for key: = range m { ret = добавить (ret, ключ) fmt.Println (cap (ret)) } возвратиться }  

Теперь сравните это с тем же кодом, но с заранее определенной мощностью.

  пакет основной импорт "fmt" func main () { fmt.Println (keys (map [string] struct {} { "собака": struct {} {}, "кошка": struct {} {}, "мышь": struct {} {}, "волк": struct {} {}, "аллигатор": struct {} {}, })) } func keys (m map [string] struct {}) [] string { ret: = make ([] строка, 0, len (m)) fmt.Println (cap (ret)) for key: = range m { ret = добавить (ret, ключ) fmt.Println (cap (ret)) } возвратиться }  

В первом примере кода наша емкость начинается с 0 , а затем увеличивается до 1 , 2 , 4 и, наконец, 8 , что означает, что нам приходилось выделять новый массив 5 раз, и кроме того, последний массив, используемый для поддержки нашего среза, имеет емкость 8 , что больше, чем нам в конечном итоге нужно.

С другой стороны, наша вторая выборка начинается и заканчивается с той же емкостью ( 5 ), и ее нужно выделить только один раз в начале функции keys () . Мы также не тратим лишнюю память и возвращаем срез с массивом идеального размера, поддерживающим его.

Не оптимизируйте слишком много

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

Это не только помогает улучшить производительность вашего приложения, но также может помочь немного прояснить ваш код, явно указав взаимосвязь между размером вашего ввода и размером вашего вывода.

Вкратце…

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

Для дальнейшего чтения я настоятельно рекомендую следующие статьи из Go Blog:

Я, вероятно, замалчил некоторые детали, чтобы упростить понимание общих концепций, описанных в этом посте, но если вы чувствуете, что что-то явно не так или вводит в заблуждение, не стесняйтесь писать мне по электронной почте (jon@calhoun.io) или писать мне на Slack Gopher (@jon), и я буду рад обсудить и обновить пост.

Изучите веб-разработку с Go!

Подпишитесь на мою рассылку, и я пришлю вам БЕСПЛАТНЫЙ образец из моего курса - Веб-разработка с Go.В выборку входят несколько первых глав из книги и более 2,5 часов скринкастов.

Вы также будете получать от меня электронные письма о предстоящих курсах (включая БЕСПЛАТНЫЕ), новых сообщениях в блогах и скидках на курсы.

© 2018 Джонатан Калхун. Все права защищены.

.

Смотрите также