提问人:rayaantaneja 提问时间:9/10/2023 最后编辑:rayaantaneja 更新时间:9/10/2023 访问量:60
如何在 Swift 中抛出二传手的错误?
How to throw errors from a setter in Swift?
问:
我想知道是否有办法让 setter 在 Swift 中抛出错误。我认为这可以解决我的问题,但我找不到一种方法,这让我怀疑我是否以正确的方式构建了我的代码。这是我试图解决的问题:
我有一个名为的结构,用户可以从他们的终端进行编辑Account
struct Account {
var strikes: Int = 0
private var _monetizationLevel: Int = 1
var monetizationLevel: Int {
get { _monetizationLevel }
set {
guard strikes == 0 else { print("Please resolve copyright strike before adjusting moentization level"); return }
guard newValue <= _monetizationLevel else { print("Monetization level can only be increased by a server admin"); return }
_monetizationLevel = newValue
}
}
}
使用 Swift 对 setter 的内置支持感觉就像是编辑帐户特征的一种自然方式。例如。,(或其他)myAccount.name = "newName123"
myAccount.monetizationLevel -= 4
但是,由于对您可以编辑的内容有一定的限制,因此我认为抛出错误将是一个合适的解决方案(因为简单地打印警告感觉非常弱)。不幸的是,我无法找到让二传手抛出错误的方法。我考虑过使用抛出函数,但考虑到 Swift 有专门用于消除使用函数设置器的尴尬的内置函数,使用函数设置器似乎真的很愚蠢。为了保持一致性,我更喜欢保留 、 等的自然性的 Swift-y 解决方案。monetizationLevel
setMonetizationLevel(to: Int)
myAccount.name = "blah"
myAccount.monetizationLevel -= 5
另一方面,如果不使用函数设置器就无法实现这一点,那么重组结构的更好方法是什么?你们会怎么做?Account
答:
这已经在评论中讨论过了,没有二传手不能 - 二传手的合同很简单 - 属性值是设置的。编译器没有办法知道可以.throw
account.monetizationLevel
throw
您需要考虑的是要在何处实现业务逻辑。看起来你正在尝试在这个结构中实现业务逻辑,你说“(混合 setter 和函数)的不一致真的会困扰我:/”
如果你打算在这个结构中实现业务逻辑,那么你可能根本不应该使用 setter。大概有一些业务逻辑 - 即它们应该是 >=0strikes
也许记录罢工也应该减少货币化?
此外,您的逻辑表明只有管理员才能增加货币化,但设置者无法知道调用者是否是管理员 - 您可以将其提供给函数。
将属性公开为只读并使用函数进行设置可能是一种更好的方法。我认为它会产生一个更易于理解的 API,并将操作与实现分开。
例如:
enum AccountException: Error {
case BadCopyrightStanding
case NotPermitted
}
struct Account {
private (set) var strikes: Int
private (set) var monetizationLevel: Int
var hasStrikes: Bool {
return strikes != 0
}
mutating func recordStrike() {
self.strikes+=1
self.monetizationLevel = 1
}
mutating func clearStrike() {
self.strikes = max(self.strikes-1,0)
}
mutating func clearStrikes() {
self.strikes = 0
}
mutating func setMonitizationLevel(_ level:Int, isAdmin: Bool) throws {
guard self.strikes == 0 else {
throw AccountException.BadCopyrightStanding
}
guard isAdmin || level <= self.monitizationLevel else {
throw AccountException.NotPermitted
}
self.monetizationLevel = level
}
}
或者,如果你在其他地方实现业务逻辑,那么这应该只是一个“愚蠢的结构”,它不应该强制执行罢工和货币化之间的关系。
评论
try
Account
strikes
-1
recordStrike()
clearStike()
clearAllStrikes()
stikes
private (set)