Marmelador
Marmelador

Reputation: 1017

Unable to return nil in generic function

I am trying to understand generics better and am writing a function, that finds a key in a given dictionary with a given value. If the value is not found it should return nil.

func findKey<Key, Value: Equatable>(for value: Value, in dictionary: [Key: Value]) -> Key {
    for set in dictionary {
        if set.value == value {
            return set.key
        }
    }
    return nil //ERROR: Nil is incompatible with Type 'Key'
}

I reveice this error:

Nil is incompatible with Type 'Key'

Upvotes: 1

Views: 550

Answers (3)

Alexander
Alexander

Reputation: 63264

Alternative implementation:

extension Dictionary where Value: Equatable {
    func key(forValue v: Value) -> Key? {
        return self.first(where: { $0.value == v})?.key
    } 
}

["a": 1, "b": 2, "c": 3].key(forValue: 3) // => Optional("c")

Note that in the case where two Keys map to the same Value v, it's not deterministic which of the two Keys will be returned. To get all Keys mapping the Value v, you can do this:

extension Dictionary where Value: Equatable {
    func keys(forValue v: Value) -> [Key] {
        return self.filter{ $0.value == v}.map{ $0.key }
    } 
}

["a": 1, "b": 2, "c": 3, "d": 3].keys(forValue: 3) // => ["d", "c"]

Upvotes: 1

Donovan King
Donovan King

Reputation: 855

In order to return nil you need to return a Key Optional " Key? "

You can read more about optionals here.

func findKey<Key, Value: Equatable>(for value: Value, in dictionary: [Key: Value]) -> Key? {
   for set in dictionary {
       if set.value == value {
           return set.key
       }
   }
   return nil  
}

Upvotes: 2

Fangming
Fangming

Reputation: 25261

Your function is set to return a Key as indicated by -> Key

You cannot return a nil because Key is an unwrapped variable. Instead, you can set the function to return an Optional which means that it can either have a Key, or it can be nil. Simply add a ? after the return type

func findKey<Key, Value: Equatable>(for value: Value, in dictionary: [Key: Value]) -> Key? {
    for set in dictionary {
        if set.value == value {
            return set.key
        }
    }
    return nil
}

Upvotes: 2

Related Questions