Reputation: 5138
I'm writing some Swift code where I have an array containing a generic type:
let _data: Array<T> = T[]()
Later in my code I need to determine the type stored in the array. I tried using the type casting technique described in the documentation (although it was not used for generics).
switch self._data {
case let doubleData as Array<Double>:
// Do something with doubleData
case let floatData as Array<Float>:
// Do something with floatData
default:
return nil // If the data type is unknown return nil
}
The above switch statement results in the following error upon compilation:
- While emitting IR SIL function @_TFC19Adder_Example___Mac6Matrix9transposeUS_7Element__fGS0_Q__FT_GSqGS0_Q___ for 'transpose' at /code.viperscience/Adder/src/Adder Library/Matrix.swift:45:3 :0: error: unable to execute command: Segmentation fault: 11 :0: error: swift frontend command failed due to signal (use -v to see invocation) Command /Applications/Xcode6-Beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 254
Anybody know how I can cast my generic data to its actual type in order to take specific action?
Upvotes: 6
Views: 5736
Reputation: 5645
Suppose you have an array of buttons:
let views: [NSView] = [NSButton(), NSButton(), NSButton()]
You can use these casts:
let viewsAreButtons = views is [NSButton] // returns true
let buttonsForSure = views as! [NSButton] // crashes if you are wrong
let buttonsMaybe = views as? [NSButton] // optionally set
If you try to use as in a switch case like below, it will not work. The compiler (Swift 1.2 Xcode 6.3b1) says: "Downcast pattern of type [NSButton] cannot be used."
switch views {
case let buttons as [NSButton]:
println("Buttons")
default:
println("something else")
}
Call it a limitation. File a radar with your use case. The Swift team really seams to be listening for feedback. If you really want to get it to work, you can define your own pattern matching operator. In this case it would be something like this:
struct ButtonArray { }
let isButtonArray = ButtonArray()
func ~=(pattern: ButtonArray, value: [NSView]) -> Bool {
return value is [NSButton]
}
Then this works:
switch views {
case isButtonArray:
println("Buttons") // This gets printed.
default:
println("something else")
}
Try it in a Playground. Hope it helps!
Upvotes: 1
Reputation: 1672
In swift, as
operator is something like dynamic_cast
in C++, which can be used to down cast an object.
Say you have an object a
of type A
, and you can write let a as B
only when type B
is identical to type A
, or B
is a sub-class of A
.
In your case, apparently Array<T>
cannot always be down cast to Array<Double>
or Array<Float>
, so compiler reports errors.
A simple fix is to convert to AnyObject
first, and then downcast to Array<Double>
or Array<Float>
:
let anyData: AnyObject = self._data;
switch anyData {
case let doubleData as? Array<Double>: // use as? operator, instead of as,
// to avoid runtime exception
// Do something with doubleData
case let floatData as? Array<Float>:
// Do something with floatData
default:
return nil // If the data type is unknown return nil
Upvotes: 2