使用 Swift 中的动态值初始化 属性 包装器 5

Initialise property wrapper with dynamic values in Swift 5

场景:

  1. 我想要不同类型的债券,它们有一个最小值, 灵活利率当前债券价值(根据某种逻辑计算)和债券增长预测。

  2. 每当债券价值 超过最小值,则增长预测变为 升值和贬值反之亦然。

  3. 我可以有多个 拥有自己的一套价值观。

我正在尝试使用 属性 包装器,这样我就不会为每个键复制相同的行为:

 @propertyWrapper
struct BondValue {
    private var bondCurrentWorth: Int
    private var minimumValue: Int
    private var flexiInterest: Int

    var projectedValue: BondGrowth = .appreciating // The projected value projects the growth for the bond

    var wrappedValue: Int {

        get {
            return bondCurrentWorth
        }

        set {
            bondCurrentWorth = newValue + (newValue * flexiInterest/100)
            projectedValue = bondCurrentWorth < minimumValue ? .depriciating : .appreciating
        } 
 }

    init(wrappedValue: Int = 0, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.minimumValue = minimumValue
        self.flexiInterest = flexiInterest
        self.bondCurrentWorth = value
    }
}

不创建任何债券,我这样做:

struct FoodBond {
    var bondName: String
    @BondValue(minimumValue: 200, flexiInterest: 30, value: 200) var value = 30

    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
    }
}

问题陈述: - 我无法使用动态值初始化债券值。

可能的解决方法: 在下面的实现中,我将使用与普通结构相同的方法。尽管文档中也指定了这种使用 属性 包装器的方式,但我会失去 属性 包装器的句法风格。

You could write code that uses the behavior of a property wrapper, without taking advantage of the special attribute syntax. For example, here’s a version of SmallRectangle from the previous code listing that wraps its properties in the TwelveOrLess structure explicitly, instead of writing @TwelveOrLess as an attribute

@propertyWrapper
struct BondValue {
    private (set) var bondCurrentWorth: Int
    private (set) var minimumValue: Int
    private (set) var flexiInterest: Int

    var projectedValue: BondGrowth = .appreciating // The projected value projects the growth for the bond

    var wrappedValue: Int { .... }

    init(wrappedValue: Int = 0, minimumValue: Int, flexiInterest: Int, value: Int) { ... }
}

struct FoodBond {
    var bondName: String
    var value = BondValue(minimumValue: 0, flexiInterest: 0, value: 0) // Provide a default value

    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
        self.value = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest, value: value)
    }
}

var foodBond = FoodBond(bondName: "Food Bond", minimumValue: 200, flexiInterest: 10, value: 200)
print("Initial bond current worth - \(foodBond.value.bondCurrentWorth)")
print("Bond growth - \(foodBond.value.projectedValue)")

任何建议都会很有帮助。

参考 Swift 提案文档中 属性 包装器的 Memberwise Initialisers 部分:

Instance properties that have a property wrapper will have a corresponding parameter in the memberwise initializer, whose type will either be the original property type or the wrapper type, depending on the wrapper type and the initial value (if provided).

解法:

struct FoodBond {
    var bondName: String

    @BondValue(minimumValue: 0, flexiInterest: 0, value: 0) var bondValue = 0

    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
        _bondValue = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest, value: value)
    }
}

您可以使用不带参数的 属性 包装器并为其指定包装值的类型,然后在初始化时使用您的参数创建它:

struct FoodBond {
    var bondName: String

    @BondValue var bondValue : Int

    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
        _bondValue = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest, value: value)
    }
}