简体   繁体   中英

How do you make string optionals in swift “hashable”?

I am trying to make a function in Swift, that takes a dictionary of strings as a parameter, and returns a tuple of strings. I want the key, value pairs in the dictionary to be optionals, because I don't want my program to crash if one of the values in the tuple it returns is "nil".

func songBreakdown(song songfacts: [String?: String?]) -> (String, String, String) {
return (songfacts["title"], songfacts["artist"], songfacts["album"])
}
if let song = songBreakdown(song: ["title": "The Miracle", 
                              "artist": "U2", 
                              "album": "Songs of Innocence"]) {
println(song);
}

There is an error message on the first line that says: "Type 'String? does not conform to protocol 'Hashable'.

I tried making the key, value pair for the parameter not optionals...

func songBreak(song songfacts: [String: String]) -> (String?, String?, String?) {
    return (songfacts["title"], songfacts["artist"], songfacts["album"])
}
if let song = songBreak(song: ["title": "The Miracle", "artist": "U2", "album": "Songs of Innocence"]) {
    println(song);
}

But then there is an error message that says: "The bound value in conditional binding must be of optional type. How can I fix this?

As you already figured out, you can't use optionals as the keys of a dictionary. So, starting with your second attempt, you are getting the error because the value returned by your function is a tuple of optionals, not an optional tuple. Instead of trying to unwrap the value returned by the function, assign it to a variable and then unwrap each component:

func songBreak(song songfacts: [String: String]) -> (String?, String?, String?) {
    return (songfacts["title"], songfacts["artist"], songfacts["album"])
}

let song = songBreak(song: ["title": "The Miracle", "artist": "U2", "album": "Songs of Innocence"])

if let title = song.0 {
    println("Title: \(title)")
}
if let artist = song.1 {
    println("Artist: \(artist)")
}
if let album = song.2 {
    println("Album: \(album)")
}

As Rob Mayoff suggested in the comments, it is better style to name the tuple elements:

func songBreak(song songfacts: [String: String]) -> (title: String?, artist: String?, album: String?) {
    return (title: songfacts["title"], artist: songfacts["artist"], album: songfacts["album"])
}

let song = songBreak(song: ["title": "The Miracle", "artist": "U2", "album": "Songs of Innocence"])

if let title = song.title {
    println("Title: \(title)")
}
if let artist = song.artist {
    println("Artist: \(artist)")
}
if let album = song.album {
    println("Album: \(album)")
}

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