¿Qué es un segmento en Swift?

85

¿Qué es un segmento en Swift y en qué se diferencia de una matriz?

De la documentación, la firma de tipo del subíndice (Rango) es:

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

¿Por qué no devolver otro en Array<T>lugar de un Slice<T>?

Parece que puedo concatenar un segmento con una matriz:

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

Pero esto produce el error:

no se pudo encontrar una sobrecarga para 'subíndice' que acepta los argumentos proporcionados

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

¿Qué es una rebanada?

hjing
fuente

Respuestas:

97

El corte apunta hacia la matriz. No tiene sentido hacer otra matriz cuando la matriz ya existe y la porción puede describir la parte deseada de ella.

La adición provoca una coerción implícita, por lo que funciona. Para hacer su trabajo de asignación, que tendría que obligar a:

var list = ["hello", "world"]
var slice: Array<String> = Array(list[0..<list.count])
mate
fuente
Eso tiene sentido. ¿Se describe esto en alguna parte de la documentación?
hjing
2
Es un detalle de implementación, de verdad. ¡Probaste inteligentemente el caso de borde que revela el funcionamiento de la caja negra ...!
Matt
2
en realidad, Slice es una copia de la matriz. Después de actualizar la matriz original, el segmento no cambiará. Esto se debe a la naturaleza de la estructura. Y para la nota, el protocolo Sliceable no implica el uso del tipo Slice
Marcin
4
El lenguaje rápido ha cambiado y un segmento en realidad usa tres puntos suspensivos y no dos developer.apple.com/library/ios/documentation/General/Reference/…
Daniel Galasko
7
¿No arruinaría la correspondencia si agregara una edición simple informando a los nuevos lectores que los operadores de rango han cambiado?
Daniel Galasko
22

Nota: Esta respuesta felizmente no es válida a partir de Swift beta 3, ya que las matrices ahora son tipos de valor verdadero.


@matt es correcto, arriba - los Slice<T>puntos en la matriz. Eso parece contrario a la forma en que Swift maneja todos los otros tipos de datos con los que estamos trabajando, ya que significa que el valor del segmento puede cambiar incluso si se declara como una constante:

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

La peor parte es que el segmento actúa como una matriz. Dado que en Swift tenemos una expectativa de inmutabilidad, parece peligroso que los valores subindicados del segmento puedan cambiar sin previo aviso:

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

Pero si la matriz subyacente cambia demasiado drásticamente, se desengancha:

arr.removeAtIndex(0)                       // this detaches slice from arr
println(slice)                             // ["bonjour", "le monde"]
arr[0] = "hola"
println(slice)                             // ["bonjour", "le monde"]
Nate Cook
fuente
6
De hecho, las rebanadas funciona simplemente como matrices, como usted dice. Las matrices Swift tienen elementos mutables, incluso si se declaran inmutables . Por ejemplo, inténtalo let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour". Encontrarás que funciona. Con matrices inmutables, curiosamente, solo el tamaño es inmutable, no el contenido. (Ver "Mutabilidad de colecciones" en The Swift Programming Language )
Matt Gibson
1
"Elementos mutables" - Esto ya no es cierto
Alex Brown
14

Resumen:

Las respuestas anteriores fueron ciertas hasta Beta 3 (y pueden cambiar nuevamente en versiones futuras)

Slice ahora actúa como una matriz, pero como @matt dijo anteriormente, es efectivamente una copia superficial de una matriz debajo del capó, hasta que se realice un cambio. Los sectores (ahora) ven una instantánea de los valores originales,

También tenga en cuenta que la sintaxis de los segmentos ha cambiado:

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

Ejemplo:

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"]

Esto permite un procesamiento mucho más uniforme, ya que es más simple (en mi humilde opinión) hacer el procesamiento de listas al estilo Python: filtrar una lista para hacer otra. según la respuesta de Matt antes de Beta 3, tenía que crear una matriz temporal para mapear una porción. El nuevo código ahora es más simple:

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}]

(aunque para ser justos, foo sigue siendo un trozo)

Referencia:

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

Cambios importantes, problemas resueltos, lenguaje rápido, párrafo 1

"Array en Swift se ha rediseñado por completo para tener semántica de valor completo como Dictionary y String ... m"

Chris Conover
fuente