gpt4 book ai didi

How to throw errors from a setter in Swift?(如何在Swift中从setter抛出错误?)

转载 作者:bug小助手 更新时间:2023-10-27 20:41:21 24 4
gpt4 key购买 nike



I wanted to know if there was a way to have setters throw errors in Swift. I assume this would solve my problem but the fact that I couldn't find a way to do it makes me wonder if I've structured my code the right way. Here's the problem I'm trying to solve:

我想知道是否有一种方法可以让二传手在SWIFT中抛出错误。我认为这会解决我的问题,但我找不到方法这样做的事实让我怀疑我是否以正确的方式构建了代码。以下是我正在努力解决的问题:


I have a struct called Account which users can edit from their end

我有一个名为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
}
}
}

Using Swift's inbuilt support for setters felt like a natural way to go about editing characteristics of your account. eg. myAccount.name = "newName123", myAccount.monetizationLevel -= 4 (or whatever)

使用SWIFT内置的对setter的支持,感觉像是编辑帐户特征的一种自然方式。例如。MyAccount t.name=“newName123”,myAccount t.moneizationLevel-=4(或其他名称)


However, since monetizationLevel has certain restrictions on how much of it you can edit I assumed throwing errors would be a fitting solution to it (since simply printing warnings felts very weak). Unfortunately, I wasn't able to find a way to have the setter throw an error. I thought about using throwing functions like setMonetizationLevel(to: Int) but using function setters seemed really silly considering Swift has inbuilt ones specifically to eliminate the awkwardness of using function setters. I would prefer a Swift-y solution that preserves the naturalness of myAccount.name = "blah", myAccount.monetizationLevel -= 5, etc. just for consistency sake.

然而,由于monetizationLevel对您可以编辑的内容有一定的限制,我认为抛出错误将是一个合适的解决方案(因为简单地打印警告感觉非常弱)。不幸的是,我无法找到一种方法让setter抛出错误。我考虑过使用像setMonetizationLevel(to:Int)这样的抛出函数,但是考虑到Swift已经内置了专门用来消除使用函数setter的尴尬,使用函数setter似乎真的很愚蠢。我更喜欢Swift-y解决方案,它保留了myAccount.name =“blah”,myAccount.monetizationLevel -= 5等的自然性,只是为了保持一致性。


On the other hand, if there's no way to achieve this without using function setters what would be a better way to restructure my Account struct? How would you guys go about this?

另一方面,如果不使用函数设置器就无法实现这一点,那么重构我的帐户结构的更好方法是什么?你们会怎么做呢?


更多回答

It doesn’t work and even if it did it wouldn’t be as swifty as you suggest since you would need to use try and maybe also surround the assignment with a do/catch. It can also be problematic if a get or set contains to much logic in my opinion so my suggestion would be to use a function instead.

它不起作用,即使它起作用了,也不会像你建议的那样迅速,因为你需要使用try,也许还需要用do/Catch将任务括起来。在我看来,如果GET或SET包含太多逻辑,这也可能是有问题的,所以我的建议是改用函数。

@JoakimDanielson True. Using "try" isn't ideal but like I said I assumed error-handling would be the most fitting solution to figure out why the "set" failed. Do you have any recommendations to how I could restructure my code?

@JoakimDanielson True。使用“try”并不理想,但正如我所说的,我认为错误处理将是找出“set”失败原因的最合适的解决方案。对于如何重构我的代码,您有什么建议吗?

See my edited comment.

请参阅我编辑后的评论。

@JoakimDanielson Ah that's unfortunate that I'll have to use a function. I'll try brainstorming a way to restructure my code through cuz I'm reluctant to have a setter function just for this property. The inconsistency would really bother me :/ Thanks for the advice though!

@JoakimDanielson啊,不幸的是,我必须使用一个函数。我将试着通过头脑风暴来重新构造我的代码,因为我不愿意只为这个属性使用setter函数。这种不一致真的会让我很烦恼:/不过还是要谢谢你的建议!

The contract of a setter is simple - it sets a property. You need a more complicated contract - the operation can fail/throw. This means that you need a function. It may be that this business logic doesn't belong in Account - maybe it belongs somewhere else. For example, where do you guard against setting strikes to -1? Perhaps you shouldn't be using setters at all? Maybe there should be functions recordStrike() which increments the number of strikes and clearStike()/clearAllStrikes() which decrement/zero the count. stikes would then be a private (set) property

Setter的契约很简单--它设置一个属性。你需要一个更复杂的合同--操作可能失败/失败。这意味着您需要一个函数。可能这个业务逻辑不属于帐户--也许它属于其他地方。例如,你在哪里防止将打击设置为-1?也许您根本不应该使用setter?也许应该有函数recordStrike()递增罢工次数,而leararStike()/clearAllStrikes()函数递减/清零计数。因此,Stikes将成为私有(集合)属性

优秀答案推荐

This has already been discussed in comments, no setters cannot throw - the contract of a setter is simple - the property value is set. There is no way for the compiler to know that account.monetizationLevel can throw.

这已经在评论中讨论过了,没有设置器不能抛出-设置器的契约很简单-属性值被设置。编译器没有办法知道Account。moneizationLevel可以抛出。


What you need to consider is where you want to implement you business logic. It looks like you are trying to implement business logic in this struct, and you say "The inconsistency (of mixing setters and functions) would really bother me :/"

您需要考虑的是要在哪里实现业务逻辑。看起来您正在尝试在这个结构中实现业务逻辑,并且您说“(混合setter和函数)的不一致会让我非常困扰:/”


If you are going to implement business logic in this struct, then you probably shouldn't use setters at all. Presumably there is some business logic around strikes - ie they should be >=0

如果要在此结构中实现业务逻辑,则可能根本不应该使用setter。大概有一些关于罢工的商业逻辑--即它们应该>=0


Maybe recording a strike should also reduce monetisation?

或许记录一次罢工也应该减少货币化?


Also, your logic says that only admins can increase monetisation, but there is no way for the setter to know if the caller is an admin - you can provide this to a function.

此外,您的逻辑表明,只有管理员才能增加货币化,但setter无法知道调用者是否为管理员--您可以将其提供给函数。


Exposing properties as read-only and using functions for setting is possibly a better approach. I think it results in an API that is easier to understand and which separates operations from implementation.

将属性公开为只读并使用函数进行设置可能是更好的方法。我认为它会导致一个更容易理解的API,并且将操作与实现分离。


For example:

例如:


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
}
}

Or, if you are implementing business logic elsewhere, then this should just be a "dumb struct" and it should not enforce the relationship between strikes and monetisation.

或者,如果你在其他地方实现业务逻辑,那么这应该只是一个“愚蠢的结构”,它不应该强制罢工和货币化之间的关系。


更多回答

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com