简体   繁体   中英

How to call a generic function with no parameter?

Adding an extension to Array, which returns the first Int or String is easy:

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

I can define a generic version, but I am not able to figure out how to call it because it does not take any parameter. Without a parameter, I can't specify the type!

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

I can work around it by adding a dummy parameter, but this is ugly.

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")

I'd appreciate if somebody could tell me how to call firstValueOfType function (or alternative way to define a generic function cleanly).

Additional Info

"Cannot explicitly specialize a generic function" is similar, but my problem is a bit more complicated because of Optional.

I've got a great answer from OOPer, which even includes the better implementation which uses lazy.filter, instead of 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")

Thank you very much for a very quick support!

One way is assigning the result to a variable with explicit type.

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

Another is using as :

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

You can pass the type as an argument with T.Type , like so:

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

[1,2,3].firstValue(like: Int.self)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM