Що таке фрагмент у Swift?


85

Що таке зріз у Swift і чим він відрізняється від масиву?

З документації типовим підписом нижнього індексу (Range) є:

subscript(Range<Int>) -> Slice<T>

Чому б не повернути інший, Array<T>а не a Slice<T>?

Схоже, я можу об'єднати фрагмент із масивом:

var list = ["hello", "world"]
var slice: Array<String> = [] + list[0..list.count]

Але це дає помилку:

не вдалося знайти перевантаження для "нижчого індексу", який приймає надані аргументи

var list = ["hello", "world"]
var slice: Array<String> = list[0..list.count]

Що таке скибочка?

Відповіді:


97

Зріз вказує на масив. Немає сенсу створювати інший масив, коли масив уже існує, а зріз може просто описати бажану його частину.

Додавання викликає неявний примус, тому воно працює. Щоб ваше завдання працювало, вам потрібно було б примусити:

var list = ["hello", "world"]
var slice: Array<String> = Array(list[0..<list.count])

Що має сенс. Це де-небудь описано в документації?
hjing

2
Це справді деталь реалізації. Ви розумно промацали край, який виявляє роботу чорної скриньки ...!
matt

2
насправді Slice - це копія масиву. Після оновлення оригінального масиву фрагмент не буде змінюватися. Це пов’язано зі структурою. А для примітки, протокол Sliceable не передбачає використання типу Slice
Marcin,

4
Швидка мова змінилася, і фрагмент насправді використовує три еліпсиси, а не два developer.apple.com/library/ios/documentation/General/Reference/…
Даніель Галаско

7
Не зруйнувало б листування, якби ви додали просту редакцію, інформуючи нових читачів про те, що оператори діапазону змінилися?
Даніель Галаско

22

Примітка: Ця відповідь на щастя недійсна станом на Swift beta 3, оскільки масиви тепер є істинними типами значень.


@matt правильний, вгорі - Slice<T>точки в масиві. Це здається суперечним тому, як Swift обробляє всі інші типи даних, з якими ми працюємо, оскільки це означає, що значення зрізу може змінюватися, навіть якщо воно оголошено як константа:

var arr = ["hello", "world", "goodbye"]    // ["hello", "world", "goodbye"]
let slice = arr[0..2]                      // ["hello", "world"]
arr[0] = "bonjour"
println(slice)                             // ["bonjour", "world"]

Найгірше те, що зріз діє так само, як масив. Враховуючи, що в Swift ми маємо очікування незмінності, видається небезпечним те, що підписані значення фрагмента можуть змінюватися без попередження:

println(slice[1])                          // "world"
arr[1] = "le monde"
println(slice[1])                          // "le monde"

Але якщо базовий масив змінюється занадто різко, вони відчіплюються:

arr.removeAtIndex(0)                       // this detaches slice from arr
println(slice)                             // ["bonjour", "le monde"]
arr[0] = "hola"
println(slice)                             // ["bonjour", "le monde"]

6
Насправді, фрагменти працюють так само, як масиви, як ви кажете. Швидкі масиви мають змінні елементи, навіть якщо вони оголошені як незмінні . Наприклад, спробувати let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour". Ви виявите, що це працює. Як не дивно, з незмінними масивами незмінним є лише розмір , а не вміст. (Див. "Змінність колекцій" у "Швидкій мові програмування" )
Метт Гібсон,

1
"Змінні елементи" - Це вже неправда
Алекс Браун,

14

Короткий зміст:

Наведені вище відповіді були правдивими до бета-версії 3 (і можуть змінитися знову в наступних випусках)

Зараз Slice діє так само, як масив, але, як @matt сказав вище, фактично є неглибокою копією масиву під капотом, доки не буде зроблено змін. Фрагменти (зараз) бачать знімок вихідних значень,

Також зверніть увагу, що синтаксис зрізу змінився:

[from..upToButNotIncluding] -> [from..<upToButNotIncluding]

Приклад:

var arr = ["hello", "world", "goodbye"] // ["hello", "world", "goodbye"]
var arrCopy = arr
let slice = arr[0..<2]                  // ["hello", "world"]
arr[0] = "bonjour"
arr                                     // ["bonjour", "world", "goodbye"]
arrCopy                                 // ["hello", "world", "goodbye"]
slice                                   // ["hello", "world"]

Це дозволяє набагато більш рівномірно обробляти, оскільки простіше (IMHO) виконувати обробку списку стилів python - фільтрування одного списку для створення іншого. відповідно до відповіді Метта до бета-версії 3, вам потрібно було створити тимчасовий масив, щоб зіставити фрагмент. Новий код тепер простіший:

class NameNumber {
    var name:String = ""
    var number:Int = 0

    init (name:String, number:Int) {
        self.name = name
        self.number = number
    }
}

var number = 1
let names = ["Alan", "Bob", "Cory", "David"]
let foo = names[0..<2].map { n in NameNumber(name:n, number:number++) }
foo     // [{name "Alan" number 1}, {name "Bob" number 2}]

(хоча, щоб бути справедливим, foo все ще є частиною)

Довідково:

http://adcdownload.apple.com//Developer_Tools/xcode_6_beta_3_lpw27r/xcode_6_beta_3_release_notes__.pdf

Важливі зміни, вирішені проблеми, - швидка мова, пункт 1

"Масив у Swift був повністю перероблений, щоб мати повноцінну семантику, як Dictionary і String ... m"

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.