Данные ранжируются подпиской странного поведения - PullRequest
0 голосов
/ 16 июня 2019

Я играл со Swift's Data в следующем маленьком коде:

var d = Data(count: 10)
d[5] = 3
let d2 = d[5..<8]
print("\(d2[0])")

К моему удивлению, этот код создает исключение для print(), тогда как следующий код этого не делает:

var d = Data(count: 10)
d[5] = 3
let d2 = d.subdata(in: 5..<8)
print("\(d2[0])")

Я как-то понимаю, почему это происходит, но я не понимаю, почему это так устроено. Когда я использую subdata(), я получаю полную копию диапазона, поэтому индексирование действует с 0. Но когда я использую диапазон подписки [], я получаю доступ к запрошенному диапазону, в то время как индексирование такое же, как и раньше. Так что в моем первом примере d2[5] это 3.

Но мне интересно, почему он так устроен? Я не хочу делать копии моих данных, используя метод subdata(). Я просто хотел получить доступ к части моих данных с лучшей индексацией.

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

func testit(idata: Data) {
    if idata.count > 0 {
        print("\(idata.count)")
        print("\(idata[0])")
    }
}
//...
var d = Data(count: 10)
d[5] = 3
let d2 = d[5..<8]
testit(idata: d2)

Этот код действительно странный. Потому что если вы отлаживаете свой код, вы увидите, что print("\(idata.count)") печатает 3 размером idata, что правильно, но доступ к нему с помощью idata[0] создает исключение.

Есть ли причина для этого дизайна? Я ожидал, что смогу получить доступ к Data из начального индекса подписки 0, хотя это не так. Могу ли я сделать это без использования subdata(), который создает копию данных или использования дополнительных аргументов для передачи базы среза данных?

1 Ответ

1 голос
/ 16 июня 2019

d[5..<8] возвращает Data.Slice - что составляет Data.Как правило, срезы имеют общие индексы с их базовым набором, как описано в Slice.

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

Также удобно, как в этом примере, чтобы найти текстпосле второго вхождения символа в строку:

let string = "abcdefgabcdefg"

// Find first occurrence of "d":
if let r1 = string.range(of: "d") {
    // Find second occurrence of "d":
    if let r2 = string[r1.upperBound...].range(of: "d") {
        print(string[r2.upperBound...]) // efg
    }
}

Как следствие, вы никогда не должны предполагать, что индексы коллекции начинаются с нуля (если не задокументировано, как для Array.startIndex).Используйте startIndex, чтобы получить первый индекс, или first, чтобы получить первый элемент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...