Сохранение различных типов значений в массиве в Swift

В языке Swift Programming сказано: "В массиве хранится несколько значений одного и того же типа в упорядоченном списке". Но я обнаружил, что вы можете хранить несколько типов значений в массиве. Неверно ли это описание?

например.

var test = ["a", "b", true, "hi", 1]

Ответ 1

От REPL

 xcrun swift
  1> import Foundation
  2> var test = ["a", "b", true, "hi", 1]
test: __NSArrayI = @"5 objects" {
  [0] = "a"
  [1] = "b"
  [2] =
  [3] = "hi"
  [4] = (long)1
}
  3>

вы можете видеть test is NSArray, который является видом AnyObject[] или NSObject[]

Что происходит, так это то, что Foundation обеспечивает возможность преобразования числа и boolean в NSNumber. Компилятор выполнит преобразование, когда это необходимо, чтобы скомпилировать код.

Итак, теперь они имеют общий тип NSObject и поэтому выводятся как NSArray


Ваш код не компилируется в REPL без import Foundation.

 var test = ["a", "b", true, "hi", 1]
<REPL>:1:12: error: cannot convert the expression type 'Array' to type 'ArrayLiteralConvertible'

 var test:Array = ["a", "b", true, "hi", 1]
<REPL>:4:18: error: cannot convert the expression type 'Array' to type 'ExtendedGraphemeClusterLiteralConvertible'

но вы можете сделать это

var test : Any[] = ["a", "b", true, "hi", 1]

Потому что они имеют общий тип, который Any.


Примечание: AnyObject[] не будет работать без import Foundation.

var test:AnyObject[] = ["a", "b", true, "hi", 1]
<REPL>:2:24: error: type 'Bool' does not conform to protocol 'AnyObject'

Ответ 2

Чтобы инициализировать массив с произвольными типами, просто используйте var arbitraryArray = [Any]().

Ответ 3

AnyObject - это тип, и вы можете создать массив, который содержит те, которые (как подразумевает название класса) означает, что он может содержать любой тип объекта. NSArrays не привязаны к типу, и когда вы создаете массив со смешанными типами, он генерирует NSArray вместо Array. Однако я не стал бы полагаться на это, поскольку это может измениться в будущем (AnyObject [] автоматически соединяется с NSArray).

Вы можете попробовать это на игровой площадке (обратите внимание: dynamicType returns "(Metatype)", и я не был уверен, как вытащить фактический тип, поэтому я полагался на ошибку компилятора):

var x = [ 1, 2, "a" ]
x.dynamicType.description() // -> __NSArrayI

var y = [ 1, 2 ]
y.dynamicType.description() // -> Error: Array<Int>.Type does not have a member named 'description'.

var z: AnyObject[] = [ 1, 2, "a" ]
z.dynamicType.description() // -> Error: Array<AnyObject>.Type does not have a member named 'description'.

Ответ 4

Описание верное, массив хранит несколько значений одного и того же типа. Ключ состоит в том, что одно значение имеет несколько типов. То есть, например, String имеет типы String и Any; экземпляр класса Ellipse : Shape имеет типы Ellipse, Shape, AnyObject и Any.

 14> class Foo {}
 15> class Bar : Foo {}
 16> var ar1 : Array<Any> = [1, "abc", Foo(), Bar()]
ar1: Any[] = size=4 {
  [0] = <read memory from 0x7fa68a4e67b0 failed (0 of 8 bytes read)>
  [1] = { ... }
  [2] = {}
  [3] = { ... }
}
 17> ar1[0]
$R5: Int = <read memory from 0x7fa68a51e3c0 failed (0 of 8 bytes read)>
 18> ar1[1]
$R6: String = { ... }
 19> ar1[2]
$R7: Foo = {}
 20> ar1[3]
$R8: Bar = {
  lldb_expr_14.Foo = {}
}
 21> ar1[0] as Int
$R9: Int = 1

Ответ 5

В Swift 3 вы можете использовать:

var testArray = ["a",true,3,"b"] as [Any]

Ответ 6

Вместо этого вы также можете использовать структуру в вашем классе:

struct Something {
        let a: String
        let b: String?
        let boolValue: Bool
        let value: Int

        init(a: String, b: String? = nil, boolValue: Bool, value: Int) {
            self.a = a
            self.b = b
            self.boolValue = boolValue
            self.value = value
        }
}