It is not possible to pass any type of array to a function that takes the [Any] parameter as a parameter

I have an array of type [String]

 let names = ["Joffrey", "Cersei", "Mountain", "Hound"] 

I have a function that takes an array of type [Any] .

 func printItems(items: [Any]){ for item in items { print(item) } } 

Now, when I call a function with names as parameters,

 printItems(names) 

I get an error. Unable to call 'printItems' using argument list of type '([String])' .

Any is just a typealias for a protocol that all types implicitly match.

Thoughts?

+5
source share
3 answers

This is an amazing limitation of Swift. You cannot superimpose an array on the [Any] type so that you cannot pass it to a function of the [Any] . You can use map to create each element of the array:

 printItems(names.map {$0 as Any}) 

But the correct way to do this in Swift is to use Generics :

 func printItems<T>(items: [T]) { for item in items { print(item) } } let names = ["Joffrey", "Cersei", "Mountain", "Hound"] let numbers = [3.1416, 2.71818, 1.4142, 1.618034] printItems(names) // This now works printItems(numbers) // This works too 
+2
source

Although each type corresponds to Any , it is not the same as being a universal implicit superclass to which all types inherit.

When you apply a type to a protocol, you create a new value with a different structure. Therefore, for a string of type Any it must be physically converted from the String view:

 sizeof(String) // 24 bytes (on 64-bit, anyway) 

to Any view:

 sizeof(Any) // 32 bytes, includes some meta data // about what the type really is 

Since the types of values ​​are stored directly in the array, the array will have a completely different shape, so under the hood the compiler will have to do the equivalent of this:

 names.map { $0 as Any } // create a new array, with the Any versions 

Swift could automate this process for you (this happens if you pass one variable to a function that accepts Any ). But Im personally glad that this is not so, I'd rather be more explicit - suppose your array was huge, that would be a lot of processing happening implicitly under the hood.

This is different than when you have an array of reference types, all of which are pointers to the actual data and therefore are the same size and do not need to be converted when raising:

 class C { } class D: C { } let d = D() let c: C = d unsafeBitCast(d, UnsafePointer<Void>.self) // these value will unsafeBitCast(c, UnsafePointer<Void>.self) // be the same 

Thus, β€œthis array [D] is really an array from [C] ” is just a compiler question, agreeing that types can be replaced, data conversion should not occur:

 // so this works fine, // no runtime transformation needed: func f(cs: [C]) { } let ds = [D(),D()] f(ds) 

But the protocols are still different from references to superclasses when used with classes:

 protocol P { } extension C: P { } sizeofValue(C()) // 8 bytes (just a pointer) sizeofValue(C() as P) // 40 bytes func g(ps: [P]) { } g(ds) // won't compile, needs transformation 
+1
source

You need to explicitly indicate your declaration that you are declaring an array of Any, and not a specific array of types.

With your current declaration, Swift will check it on the [String] array. not like [Any] array.

To fix the problem, follow these steps:

 let names : [Any] = ["Joffrey", "Cersei", "Mountain", "Hound"] 

If you want to keep the let declaration, use AnyObject in your printItems function and it will be accepted by Swift.

 func printItems(items: [AnyObject]){ for item in items { print(item) } } 
0
source

All Articles