如何在 switch 语句中(同时)键入匹配和解包可选值?
How to type match and unwrap optional values in a switch statement (simultaneously)?
有没有办法在一个案例中结合类型匹配和展开可选值?
在下面的 playground 代码中有三个循环:
循环 A 正在使用 if let
来匹配类型并同时展开可选值。
在 循环 B 中,我用 switch
语句替换了 if let
。但是我正在使用 where
并检查 nil
,然后从这一点开始强制展开我的值。
我想知道是否有类似于 Loop C 的方法来解包值,以便我可以像在 Loop 中那样使用那些新的非可选变量A.
import Foundation
// Setup
protocol MyObjects {}
struct MyTopic: MyObjects {
let name: String?
}
struct MyQuestion: MyObjects {
let text: String?
let topic: String?
}
let topicOrQuestions: [MyObjects] = [
MyQuestion(text: "questionA", topic: "topicA"),
MyTopic(name: "topicA"),
MyTopic(name: "topicB"),
MyTopic(name: nil)
]
// Loop A:
for topicOrQuestion in topicOrQuestions {
if let name = (topicOrQuestion as? MyTopic)?.name {
print(name)
} else if let text = (topicOrQuestion as? MyQuestion)?.text, let topic = (topicOrQuestion as? MyQuestion)?.topic {
print(text, topic)
} else {
print("Error: wrong type or nil value")
}
}
// Loop B:
for topicOrQuestion in topicOrQuestions {
switch topicOrQuestion {
case let topic as MyTopic where topic.name != nil:
print(topic.name!)
case let question as MyQuestion where question.text != nil && question.topic != nil:
print(question.text!, question.topic!)
default:
print("Error: wrong type or nil value")
}
}
// Loop C (doesn't work):
for topicOrQuestion in topicOrQuestions {
switch topicOrQuestion {
case let name as MyTopic.name: // <-- Is it possible to unwrap the values here directly similar to the if let's in Loop A?
print(name)
case let text as MyQuestion.text, let topic as MyQuestion.topic:
print(text, topic)
default:
print("Error: wrong type or nil value")
}
}
/*
Current output from Loop A and B and expected output from Loop C:
questionA topicA
topicA
topicB
Error: wrong type or nil value
*/
我不认为你能在 case 中转换和解包,但有了这个扩展至少你的 Loop A
会不那么冗长:
extension MyObjects {
subscript<T: MyObjects, V>(topicOrQuestion keypath: (T) -> V) -> V? {
get {
guard let root = self as? T else { return nil }
return keypath(root)
}
}
}
你也可以写这个循环:
for topicOrQuestion in topicOrQuestions {
if let topicName = topicOrQuestion[topicOrQuestion: \MyTopic.name] as? String {
print(topicName)
}
if let questionText = topicOrQuestion[topicOrQuestion: \MyQuestion.text] as? String ,
let questionTopic = topicOrQuestion[topicOrQuestion: \MyQuestion.topic] as? String {
print(questionText, questionTopic)
}
}
// questionA topicA
// topicA
// topicB
有没有办法在一个案例中结合类型匹配和展开可选值?
在下面的 playground 代码中有三个循环:
循环 A 正在使用 if let
来匹配类型并同时展开可选值。
在 循环 B 中,我用 switch
语句替换了 if let
。但是我正在使用 where
并检查 nil
,然后从这一点开始强制展开我的值。
我想知道是否有类似于 Loop C 的方法来解包值,以便我可以像在 Loop 中那样使用那些新的非可选变量A.
import Foundation
// Setup
protocol MyObjects {}
struct MyTopic: MyObjects {
let name: String?
}
struct MyQuestion: MyObjects {
let text: String?
let topic: String?
}
let topicOrQuestions: [MyObjects] = [
MyQuestion(text: "questionA", topic: "topicA"),
MyTopic(name: "topicA"),
MyTopic(name: "topicB"),
MyTopic(name: nil)
]
// Loop A:
for topicOrQuestion in topicOrQuestions {
if let name = (topicOrQuestion as? MyTopic)?.name {
print(name)
} else if let text = (topicOrQuestion as? MyQuestion)?.text, let topic = (topicOrQuestion as? MyQuestion)?.topic {
print(text, topic)
} else {
print("Error: wrong type or nil value")
}
}
// Loop B:
for topicOrQuestion in topicOrQuestions {
switch topicOrQuestion {
case let topic as MyTopic where topic.name != nil:
print(topic.name!)
case let question as MyQuestion where question.text != nil && question.topic != nil:
print(question.text!, question.topic!)
default:
print("Error: wrong type or nil value")
}
}
// Loop C (doesn't work):
for topicOrQuestion in topicOrQuestions {
switch topicOrQuestion {
case let name as MyTopic.name: // <-- Is it possible to unwrap the values here directly similar to the if let's in Loop A?
print(name)
case let text as MyQuestion.text, let topic as MyQuestion.topic:
print(text, topic)
default:
print("Error: wrong type or nil value")
}
}
/*
Current output from Loop A and B and expected output from Loop C:
questionA topicA
topicA
topicB
Error: wrong type or nil value
*/
我不认为你能在 case 中转换和解包,但有了这个扩展至少你的 Loop A
会不那么冗长:
extension MyObjects {
subscript<T: MyObjects, V>(topicOrQuestion keypath: (T) -> V) -> V? {
get {
guard let root = self as? T else { return nil }
return keypath(root)
}
}
}
你也可以写这个循环:
for topicOrQuestion in topicOrQuestions {
if let topicName = topicOrQuestion[topicOrQuestion: \MyTopic.name] as? String {
print(topicName)
}
if let questionText = topicOrQuestion[topicOrQuestion: \MyQuestion.text] as? String ,
let questionTopic = topicOrQuestion[topicOrQuestion: \MyQuestion.topic] as? String {
print(questionText, questionTopic)
}
}
// questionA topicA
// topicA
// topicB