Reputation: 3136
I am looking for a better way to access the variables of a struct. A json query fills an array of this struct:
struct AnimalInfo: Codable {
var English: String
var French: String
var Spanish: String
}
An example:
let theDog = AnimalInfo(English: "Dog", French: "Chien", Spanish: "Perro")
The languages are in an array, the current one is always changing. I keep track with a pointer:
let languageListArray = ["English", "French", "Spanish"]
let currentLanguage = languageListArray[2]
I'd like to be able to retrieve the value from the struct with this information, something along the lines of:
let myString = theDog.currentLanguage // = "Perro"
.. but of course that is not possible. The best I've come up with so far is a switch:
switch currentLanguage {
case "English":
return theDog.English
case "French":
return theDog.French
case "Spanish":
return theDog.Spanish
}
But this is ugly, and doesn't scale well with many languages! Anyone have a better way?
Upvotes: 0
Views: 79
Reputation: 3857
It's possible without keyPaths too
protocol Translated {
var english: String { get }
var french: String { get }
var spanish: String { get }
}
struct Animal: Codable, Translated {
let english: String
let french: String
let spanish: String
}
let english: (Translated) -> String = { $0.english }
// or you can write that as a key path \.english
let french: (Translated) -> String = { $0.french }
let spanish: (Translated) -> String = { $0.spanish }
let theDog = Animal(english: "Dog", french: "Chien", spanish: "Perro")
english(theDog) // Dog
french(theDog) // Chien
var currentLanguage: (Translated) -> String = english
currentLanguage(theDog) // Dog
currentLanguage = french
currentLanguage(theDog) // Chien
If you want your dot syntax then:
extension Translated {
var inCurrentLanguage: String { currentLanguage(self) }
}
theDog.inCurrentLanguage // Chien
You can indeed use key paths to specify your function without having to name it, e.g.
// no need to define/name these functions
// let spanish: (Translated) -> String = { $0.spanish }
currentLanguage = \.spanish
theDog.inCurrentLanguage // Perro
Upvotes: 2
Reputation: 285069
but of course that is not possible
Oh, it is possible if you use key paths
struct AnimalInfo: Codable {
let english: String
let french: String
let spanish: String
}
let theDog = AnimalInfo(english: "Dog", french: "Chien", spanish: "Perro")
let languageListArray : [KeyPath<AnimalInfo,String>] = [\.english, \.french, \.spanish]
let currentLanguage = languageListArray[2]
let myString = theDog[keyPath: currentLanguage] // = "Perro"
Upvotes: 2