Reputation: 89
I'm trying to solve an string assignment problem in Swift: Here we have a struct:
struct Student {
var name: String
var id: String
var mentor: String?
var grade: String?
}
And we want to parse it into a string, something like:
if (mentor != nil && grade != nil) {
return "Student info: name:" + name + " id:" + id + " mentor:" + mentor! + " grade:" + grade! + "."
} else if (mentor != nil) {
return "Student info: name:" + name + " id:" + id + " mentor:" + mentor! + "."
} else if (grade != nil) {
return "Student info: name:" + name + " id:" + id + " grade:" + grade! + "."
} else {
return "Student info: name:" + name + " id:" + id + "."
}
I'm new to the Swift, the code above is based on other language's experience, I'm wondering if there's any more concise way to achieve that in Swift? Like deal with optional toString(), if it's nil then return a empty string ""?
Upvotes: 1
Views: 313
Reputation: 131398
Alexander's answer is good, and makes good use of the higher order function map(), but it might be a bit over your head if you're just starting out. You could simplify your code quite a bit with judicious use of if let
"optional binding":
var result = "Student info: name:" + name + " id:" + id
if let mentor = mentor {
result += " mentor:" + mentor
}
if let grade = grade {
result += " grade:" + grade
}
result += "."
return result
Or rewritten to avoid the +
operator:
var result = "Student info: name:\(name) id:\(id)"
if let mentor = mentor {
result.append(" mentor:\(mentor)")
}
if let grade = grade {
result.append(" grade:\(grade)")
}
result.append(".")
return result
Upvotes: 3
Reputation: 63167
Here are the improvements I would make:
Firstly, you should remove the unnecessary parentheses around the if
predicates. You may be used to them from other C-like languages, but in Swift they're just noise.
Secondly, you should replace string concatenation (+
) with interpolation. It has much faster compile times (operator type inference slows the compiler substantially), and will soon (with the rework of string interpolation) have better runtime performance (no redundant string allocation).
Next, I would use Optional.map
to construct all the parts of the sentence that are optional. Then, I would default them to the empty string, if they're nil
.
Then, I would take all the segments of the string, and join them together with a space as a separator:
struct Student {
var name: String
var id: String
var mentor: String?
var grade: String?
}
extension Student: CustomStringConvertible {
var description: String {
let start = "Student info:"
let nameSegment = "name: \(self.name)"
let idSegment = "id: \(self.id)"
let mentorSegment = self.mentor.map { "mentor: \($0)" } ?? ""
let gradeSegment = self.grade.map { "grade: \($0)" } ?? ""
return [start, nameSegment, idSegment, mentorSegment, gradeSegment].joined(separator: " ")
}
}
print(Student(name: "Bob", id: "id123", mentor: "Mr. Mentor", grade: "123"))
// => Student info: name: Bob id: id123 mentor: Mr. Mentor grade: 123
Upvotes: 1