2016-07-30 6 views
3

Добавление расширений в массив, который возвращает первый Int или строки легко:Как вызвать общую функцию без параметров?

extension Array { 
    func firstInt() -> Int? { 
     return self.flatMap{$0 as? Int}.first 
    } 
    func firstString() -> String? { 
     return self.flatMap{$0 as? String}.first 
    } 
} 

let a1:[AnyObject?] = [nil, "abc", 3, 4] 
let a2:[AnyObject?] = [nil, [3], [ "foo":"bar" ]] 
print(a1.firstInt()) // Optional(3) 
print(a2.firstInt()) // nil 
print(a1.firstString()) // Optional("abc") 
print(a2.firstString()) // nil 

я могу определить общую версию, но я не могу понять, как назвать его, потому что он не принимает какой-либо параметр. Без параметра я не могу указать тип!

extension Array { 
    func firstValueOfType<T>() -> T? { 
     return self.flatMap{$0 as? T}.first 
    } 
} 
// I can't figure out how to call this method! 

Я могу обойти это, добавив параметр фиктивной ошибки, но это уродливо.

extension Array { 
    func firstValueLike<T>(_:T) -> T? { 
     return self.flatMap{$0 as? T}.first 
    } 
} 

let a1:[AnyObject?] = [nil, "abc", 3, 4] 
print(a1.firstValueLike(1)) // Optional(3) 
print(a1.firstValueLike("")) // Optional("abc") 

Я был бы признателен, если кто-то может сказать мне, как вызвать функцию firstValueOfType (или альтернативный способ определения обобщенной функции чисто).

Дополнительная информация

«Не удается явно специализировать обобщенную функцию» похожа, но моя проблема является немного более сложным из-за Опциональный.

У меня есть отличный ответ от OOPer, который даже включает в себя лучшую реализацию, которая использует lazy.filter, а не flatMap.

extension Array { 
    func firstValueOfType<T>() -> T? { 
     return self.lazy.filter {$0 is T}.first as? T 
    } 
} 

let a1:[AnyObject?] = [nil, "abc", 3, 4] 
print(a1.firstValueOfType() as Int?) // Optional(3) 
print(a1.firstValueOfType() as String?) // Optional("abc") 

Большое спасибо за очень быструю поддержку!

+0

Возможный дубликат [Невозможно явно специализировать обобщенную функцию] (http://stackoverflow.com/questions/27965439/cannot-explicitly-specialize-a-generic-function) –

ответ

3

Один из способов - присвоить результат переменной с явным типом.

let i: Int? = a1.firstValueOfType() 
print(i) // Optional(3) 
let s: String? = a1.firstValueOfType() 
print(s) // Optional("abc") 

Другой использует as:

print(a1.firstValueOfType() as Int?) // Optional(3) 
print(a1.firstValueOfType() as String?) // Optional("abc") 
+0

Мне нравится этот ответ. Спасибо! –

+2

@LeoDabus, это не повторяет весь массив: 'self.lazy.filter {$ 0 is T}. First as? T' – OOPer

+0

@LeoDabus, игровая площадка не является хорошим местом для подсчета фактического количества итераций. Попробуйте 'self.lazy.filter {print ($ 0); return $ 0 есть T}. First as? T', и посмотрите, сколько строк напечатано. – OOPer

2

Вы можете передать тип в качестве аргумента с T.Type, например, так:

extension Array { 
    func firstValue<T>(like type: T.Type) -> T? { 
     return self.flatMap{$0 as? T}.first 
    } 
} 

[1,2,3].firstValue(like: Int.self) 
Смежные вопросы