Почему верхнее значение диапазона среза больше, чем возвращено? [Дубликат]

Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.

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

  1. Ваша точка входа (ов) выполняется в результате события. Например, в браузер загружается тег сценария с кодом. (Соответственно, поэтому вам, возможно, придется заботиться о готовности страницы запускать ваш код, если он требует, чтобы элементы dom были сконструированы первыми и т. Д.)
  2. Ваш код выполняется до завершения, однако многие асинхронные вызовы, которые он делает, без выполнения каких-либо ваших обратных вызовов, включая запросы XHR, установку тайм-аутов, обработчиков событий dom и т. д. Каждый из этих обратных вызовов, ожидающих выполнения, будет находиться в очереди, ожидая, что их очередь будет запущена после других событий
  3. Каждый отдельный обратный вызов XHR-запроса, установленного таймаута или dom события после вызова будет завершен.

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

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

5
задан ThunderCat 17 November 2014 в 06:18
поделиться

2 ответа

Это полностью согласуется, и есть, конечно, другие способы сделать это (например, Matlab использует массивы, первый индекс которых равен 1). Выбор действительно сводится к тому, какие свойства вы хотите. Как оказалось, использование 0-индексированных массивов, где slicing является инклюзивным-эксклюзивным (то есть срез от a до b включает элемент a и исключает элемент b) имеет некоторые действительно приятные свойства, и, следовательно, это очень распространенный выбор. Вот несколько преимуществ.

Преимущества 0-индексированных массивов и инклюзивно-эксклюзивных разрезов

(обратите внимание, что я использую терминологию, отличную от Go, поэтому я расскажу о массивах в том, что C или Java будут говорить о них. Массивы - это то, что Go вызывает срезы, а срезы - субмассивы (т. е. «срез от индекса 1 к индексу 4»))

  • Арифметические операции указателя. Если вы находитесь на языке типа C, массивы на самом деле просто указывают на первый элемент массива. Таким образом, если вы используете 0-индексированные массивы, вы можете сказать, что элемент в index i - это просто элемент, на который указывает указатель массива плюс i . Например, если у нас есть массив [3 2 1] с адресом массива, равным 10 (и считая, что каждое значение занимает один байт памяти), тогда адрес первого элемента равен 10 + 0 = 10, адрес второго - 10 + 1 = 11 и т. д. Короче говоря, это делает математику простой.
  • Длина среза также является местом для его среза. То есть для массива arr, arr[0:len(arr)] является только arr. Это очень полезно на практике. Например, если я назову n, _ := r.Read(arr) (где n - количество байтов, прочитанных в arr), тогда я могу просто сделать arr[:n], чтобы получить срез arr, соответствующий фактически записанным данным в arr.
  • Индексы не перекрываются. Это означает, что если у меня есть arr[0:i], arr[i:j], arr[j:k], arr[k:len(arr)], эти срезы полностью покрывают arr. Вы можете нередко находить разбиение массива на такие подрезки, как это, но оно имеет ряд связанных преимуществ. Например, рассмотрим следующий код для разбиения массива на основе неотрицательных целых чисел:
    func consecutiveSlices(ints []int) [][]int {
        ret := make([][]int, 0)
        i, j := 0, 1
        for j < len(ints) {
            if ints[j] != ints[j-1] + 1 {
                ret = append(ret, ints[i:j])
                i = j
            }
        }
        ret = append(ret, ints[i:j])
    }
    

(этот код, очевидно, не справляется с некоторыми краевыми случаями, но вы получаете идею )

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

Если кто-то может подумать больше, пожалуйста, не стесняйтесь отредактируйте этот ответ и добавьте их.

9
ответ дан James Henstridge 31 August 2018 в 12:20
поделиться

Спецификация языка программирования Go

Типы срезов

Выражения фрагментов

Для строки, массива, указателя на массив или среза a первичное выражение

a[low : high]

создает подстроку или срез. Индексы low и high определяют, какие элементы операнда a появляются в результате. Результат имеет индексы начиная с 0 и длины, равной high - low.

Для удобства любой из индексов можно опустить. Недостающий низкий индекс по умолчанию равен нулю; Отсутствует высокий индекс по умолчанию для длины разрезанного операнда

Для массивов или строк индексы находятся в диапазоне, если 0 & lt; = низкий & lt; = высокий & lt; = len (a), в противном случае они являются вне диапазона. Для срезов верхняя граница индекса - это колпачок емкости (а), а не длина. Постоянный индекс должен быть неотрицательным и быть представленным значением типа int; для массивов или постоянных строк постоянные индексы также должны находиться в зоне действия. Если оба индекса являются постоянными, они должны удовлетворять минимуму & lt; = высокий. Если индексы находятся вне допустимого диапазона во время выполнения, возникает паника во время выполнения.

Для q := p[m:n], q представляет собой фрагмент p, начинающийся с индекса m для длины элементов n-m.

2
ответ дан peterSO 31 August 2018 в 12:20
поделиться
Другие вопросы по тегам:

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