¿Por qué las operaciones de inserción de matriz Swift y removeAtIndex se comportan de manera inconsistente?

Creo que es legal intercambiar el 0º y 1º elemento de una matriz Swift de la siguiente manera:

  • llame a removeAtIndex en el índice 0, que vuelve a barajar el primer elemento al índice 0
  • inserte el elemento eliminado en el índice 1.

Pero estoy viendo un comportamiento inconsistente según cómo lo codifique.

Código

func test() { class Test { var array = ["foo", "bar"] func swap1() { // PRODUCES STRANGE RESULT array.insert(array.removeAtIndex(0), atIndex:1) print("---swap1---", xs:array) } func swap2() { // PRODUCES EXPECTED RESULT let item = array.removeAtIndex(0) array.insert(item, atIndex:1) print("---swap2---", xs:array) } func swap3() { // PRODUCES EXPECTED RESULT var array = ["foo", "bar"] array.insert(array.removeAtIndex(0), atIndex:1) print("---swap3---", xs:array) } func print(fn: String, xs: [String]) { println(fn) for x in xs { println(x) } } } Test().swap1() Test().swap2() Test().swap3() } 

Salida

 ---swap1--- foo foo bar ---swap2--- bar foo ---swap3--- bar foo 

Inesperadamente (para mí), swap1 () clona el elemento 0 en lugar de eliminarlo, como se puede ver en la repetición "foo" en el resultado de swap1 anterior. Las características que parecen producir este comportamiento son

  • pasando el resultado de removeAtIndex () como el primer parámetro a la inserción () llamada, en lugar de almacenarlo en una constante intermedia (último hecho por swap2 ())
  • operando en una variable de miembro de class en lugar de una variable local de function (última hecha por swap3 ()).

Mi pregunta: ¿por qué swap1 () se comporta de manera diferente?

Tienes dos mutadores de array en la misma statement. Esto generalmente es una mala idea y da como resultado un comportamiento indefinido. Es la misma razón por la que no quieres hacerlo:

 a = a++ + a++; 

Desde el punto de vista humano, está claro que primero está eliminando un elemento y luego agregándolo nuevamente al set del que se ha eliminado.

Desde el punto de vista del comstackdor, debe hacer 3 cosas para modificar la matriz: 1) leer los contenidos de la matriz original, 2) modificar los contenidos y 3) escribirlos nuevamente. El comstackdor tiene que hacer esto dos veces en la statement:

 array.insert(array.removeAtIndex(0), atIndex:1) 

Esperabas que el comstackdor hiciera esto:

 1) temp1 = array 2) temp1.removeItem 3) array = temp1 4) temp2 = array 5) temp2.addItem 6) array = temp2 

pero en lugar de eso lo hizo:

 1) temp1 = array 2) temp2 = array 3) temp2.removeItem 4) array = temp2 5) temp1.addItem 6) array = temp1 

El order de operaciones del comstackdor es admisible, por lo que no debe poner dos mutantes en la misma statement.

Esto parece ser un efecto secundario de cómo se manejan las matrices en Swift. Creo que Apple todavía está intentando descubrir la mejor manera de manejar arreglos mutables / inmutables en Swift, y es probable que este comportamiento cambie (y que ya haya cambiado en las betas.

Aquí hay un buen artículo (o una secuencia de artículos que detalla algunos de los comportamientos y cambios hasta el momento):

http://blog.human-friendly.com/swift-arrays-the-bugs-the-bad-and-the-ugly-incomplete