Swift 如何安全退回超出其范围的未包装的可选产品?
我是个笨蛋,请容忍我:Swift 如何安全退回超出其范围的未包装的可选产品?,swift,Swift,我是个笨蛋,请容忍我: func createEmployeeCode() -> String? { let email = UserDefaults.standard.object(forKey: "email_Saved") as? String let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String if let emailString = em
func createEmployeeCode() -> String? {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String
if let emailString = email,
let employeeCodeString = employeeCode {
return (emailString+employeeCodeString)
}
return (emailString+employeeCodeString) //ERROR: Use of unresolved identifier 'employeeCodeString' & Use of unresolved identifier 'emailString'
}
我理解错误显示的原因是因为我试图在这里返回不同范围内的内容,但如何让函数在没有“可选[…]”标记的情况下同时返回两个字符串?(旁注:使用UserDefaults.standard.string(forKey:)
)
问题是,你不知道这些字符串是否同时存在——如果它们存在,你已经有了一个很好的if let
返回你的答案。现在的问题是,如果一个或两个都是nil
,您想做什么?也许您希望从整个函数返回nil
。如果是,
func createEmployeeCode() -> String? {
let email = UserDefaults.standard.string(forKey: "email_Saved")
let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved")
if let emailString = email,
let employeeCodeString = employeeCode {
return (emailString+employeeCodeString) //successful unwrapping, let's concatenate!
}
return nil //if one or both `if let`s fail, we end up here
}
当然,在这种“坏”情况下,你可以随心所欲。也许你想展示你所有的弦。在这种情况下:
func createEmployeeCode() -> String {
let email = UserDefaults.standard.string(forKey: "email_Saved")
let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved")
return (email ?? "") + (employeeCode ?? "") //this works in the "good" case, too, and uses the nil coalescing operator `??`
}
在本例中,您可以看到返回值不再是可选的。这是因为即使两个字符串都不存在,它也会连接两个空字符串。如果感觉不舒服,您可以保留可选的返回值,并在返回前进行快速检查:
if email == nil && employeeCode == nil { return nil }
当从
userDefaults
返回值时,您试图将其作为对象而不是string
func createEmployeeCode() -> String? {
let email:String = UserDefaults.standard.string(forKey: "email_Saved") ?? ""
let employeeCode:String = UserDefaults.standard.string(forKey: "employeeCode_Saved") ?? ""
let emailString = "\(email)\(employeeCode)"
return emialString
}
根据你想要达到的目标,有不同的方法来解决这个问题
如果您始终希望创建员工代码
(即使代码为空):
尝试使用“nil
合并运算符”。
func createEmployeeCode()->字符串{
让email=UserDefaults.standard.object(forKey:“email\u已保存”)作为?字符串??“
让employeeCode=UserDefaults.standard.object(forKey:“employeeCode\u已保存”)作为?字符串??“
返回(电子邮件+员工代码)
}
要解释这里发生的事情:
我们正在展开电子邮件
,如果找不到电子邮件
,则默认值为空字符串,“”
我们对employeeCode
也采取同样的做法
虽然这不是一种解决所有未包装问题的方法,但它适合您的电子邮件
和员工代码
,因为您总是希望根据原始问题返回一些内容。我还将返回类型更改为非可选
如果员工代码必须始终包含一封电子邮件
和以及一封代码
,那么如果找不到其中一封,我们希望返回nil
尝试使用guard
语句。guard语句非常适合验证,可读性非常强:
func createEmployeeCode()->字符串?{
guard let email=UserDefaults.standard.object(forKey:“email_已保存”)为?字符串else{return nil}
guard让employeeCode=UserDefaults.standard.object(forKey:“employeeCode_已保存”)作为?字符串else{return nil}
返回(电子邮件+员工代码)
}
以下是我希望在普通生产应用程序中实现的方法
(在普通的生产应用程序中,你不会这么做!但这就是你要寻找的“习惯用语”)
请注意,返回在很大程度上是没有意义的-在有问题的应用程序中,如果其中一个守卫打破了,你就“完蛋了”。我可能只会返回一个空白字符串(或者更可能是“name\u error”之类的内容),因为此时应用程序架构已经彻底崩溃了。尝试以下功能:
func createEmployeeCode() -> String {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String
return [email, employeeCode].compactMap { $0 }.joined(separator: "")
}
如果其中一个为零或两者都存在,它将返回email或employeeCode或email+employeeCode;如果两者都漏掉,它将返回空字符串 确切的错误是什么?NewCoder,你真正要找的是“守卫”-见答案。这就是您在这里使用的“惯用语”。您不应该只使用?
来消除错误。当然,编译器没有抱怨,但是现在您可以createEmployeeCode()
并返回”
,这显然是没有意义的。我建议不要在函数中添加后缀(如果可能的话)
,除非函数在静默状态下失败。基于他们的反馈,开发人员应该很清楚这一点IDE@Chackle是的,这是一个有趣的问题。我在“代码应该是自文档化的”阵营,也就是“长得离谱的变量名”阵营。这类事情需要讨论。干杯
func createCodeIfPossible() -> String? {
guard let e = UserDefaults.standard.object(forKey: "email_Saved") else {
print("serious problem, there's no email saved")
// at this point the app is completely buggered, so give up
return ""
}
guard let c = UserDefaults.standard.object(forKey: "employeeCode_Saved") else {
print("serious problem, there's no code saved")
// at this point the app is completely buggered, so give up
return ""
}
return e + c
}
func createEmployeeCode() -> String {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String
return [email, employeeCode].compactMap { $0 }.joined(separator: "")
}