Why does the following Array extension crash if the array used with it is of type UInt, but works if the array is of type Int or String?
extension Array
{
func indexOf<T:Equatable>(value:T) -> Int?
{
for (i, val) in enumerate(self)
{
if (val as T == value)
{
return i;
}
}
return nil;
}
}
var a:[UInt] = [243, 234, 1, 212, 3, 56, 88, 11, 77];
var i = a.indexOf(234);
Error produced:
Playground execution failed: error: Execution was interrupted, reason: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
* thread #1: tid = 0x27a3c, 0x00000001079d3f27 libswift_stdlib_core.dylibswift_dynamicCast + 1063, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
* frame #0: 0x00000001079d3f27 libswift_stdlib_core.dylib
swift_dynamicCast + 1063
frame #1: 0x00000001137bbbc8
The problem is that the T: Equatable
that you define is unrelated to the T
that is stored in the array. When you do val as T
, you are converting from the array value type to your new local T
that is required to be equatable.
When you call indexOf
with a literal, it is not being forced into the same type as is stored in a
because the type is not enforced to match by your extension.
You are better off with a function to get the index of an object in an array:
func indexOfObject<T : Equatable>(object: T, inArray collection: [T]) -> Int? {
var index : Int = 0
for testObject in collection {
if testObject == object {
return index
}
index++
}
return nil
}
That strictly enforces that the T
type is equatable and matches the type of the object passed in.
Better yet, you might want to use an extension like this:
extension Array {
func indexOfObjectPassingTest(test: (object: T) -> Bool) -> Int? {
var index : Int = 0
for object in self {
if test(object: object) {
return index
}
index++
}
return nil
}
}
That is more flexible and allows you to do:
var i = a.indexOfObjectPassingTest({$0 == 234})
Notice also that I do not define T
for my method because it is already defined in the Array itself.