1

I've written an extension that searches a Collection for an object of a certain type.

extension Collection {
    /// Finds and returns the first element matching the specified type or nil.
    func findType<T>(_ type: T.Type) -> Iterator.Element? {
        if let index = (index { (element: Iterator.Element) in
            String(describing: type(of: element)) == String(describing: type) }) {
            return self[index]
        }
        return nil
    }
}

Now in Xcode 9 / Swift 4, the snippet type(of: element)) is underlined with error

Non-nominal type 'T' does not support explicit initialization

The error is strange because I'm not initializing an object.

This answer https://stackoverflow.com/a/46114847/2854041 suggests that perhaps it's a type issue - did the String(describing:) initializer change in Swift 4?

Paulw11
  • 108,386
  • 14
  • 159
  • 186
Andrew Schreiber
  • 14,344
  • 6
  • 46
  • 53
  • 4
    Why would you do `String(describing: type(of: element)) == String(describing: type)`, when you can directly compare Type variables and there's also `is` for checking types? – Dávid Pásztor Sep 20 '17 at 20:45

2 Answers2

7

You shouldn't be using String(describing:) to compare values and especially shouldn't be using it to compare types. Swift have built in methods for both. For checking if a variable is of a certain type, you can use the is keyword.

Moreover, you can also take advantage of the built in first(where:) method and check the type inside the closure.

extension Collection {
    /// Finds and returns the first element matching the specified type or nil.
    func findType<T>(_ type: T.Type) -> Iterator.Element? {
        return self.first(where: {element in element is T})
    }
}

Test data:

let array: [Any] = [5,"a",5.5]
print(array.findType(Int.self) ?? "Int not found")
print(array.findType(Double.self) ?? "Double not found")
print(array.findType(Float.self) ?? "Float not found")
print(array.findType(String.self) ?? "String not found")
print(array.findType(Bool.self) ?? "Bool not found")

Output:

5
5.5
Float not found
a
Bool not found
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
4

Here is the error I am getting enter image description here

Its getting confused with the type(of: and the argument type.

After changing T.Type argument name. Its working :

extension Collection {
    /// Finds and returns the first element matching the specified type or nil.
    func findType<T>(_ typeT: T.Type) -> Iterator.Element? {
        if let index = (index { (element: Iterator.Element) in
        String(describing: type(of: element)) == String(describing: typeT) }) {
            return self[index]
        }
        return nil
    }
}
Vini App
  • 7,339
  • 2
  • 26
  • 43