【问题标题】:How to change a value of struct that is in array?如何更改数组中结构的值?
【发布时间】:2017-01-15 19:53:58
【问题描述】:

我在我的项目中使用 swift。

我有一个名为 Instrument 的结构数组。后来我做了一个从数组返回特定​​Instrument 的函数。然后我想更改其属性之一的值,但此更改未反映在数组中。

我需要这个数组来包含里面元素的所有变化。您认为这里的最佳做法是什么?

  • Instrumentstruct 更改为 class
  • 不知何故重写了从数组返回Instrument的函数。

我现在使用这个功能:

func instrument(for identifier: String) -> Instrument? {
  if let instrument = instruments.filter({ $0.identifier == identifier }).first {
    return instrument
  }
  return nil
}

我从结构开始,因为众所周知 swift 是用于结构的语言,我想了解何时使用 structclass

谢谢

【问题讨论】:

  • 请注意,您可以使用first(where:) 而不是filter(_:)first
  • 结构是值类型。更改属性后,您必须将项目分配回数组。但不要与框架抗争!如果需要引用类型,请使用类。
  • 在这种情况下,数组是一个合适的选择吗?似乎将identifiers 映射到Instruments 的字典将是一个不错的选择
  • 好的,看来我需要切换到字典并使用引用类型。谢谢

标签: arrays swift struct


【解决方案1】:

使用struct Instrument数组,您可以获得具有特定标识符的Instrument的索引,并使用它来访问和修改Instrument的属性。

struct Instrument {
    let identifier: String
    var value: Int
}

var instruments = [
    Instrument(identifier: "alpha", value: 3),
    Instrument(identifier: "beta", value: 9),
]

if let index = instruments.index(where: { $0.identifier == "alpha" }) {
    instruments[index].value *= 2
}

print(instruments) // [Instrument(identifier: "alpha", value: 6), Instrument(identifier: "beta", value: 9)]

【讨论】:

  • instruments.index 现在是 instruments.firstIndex
  • 反应热烈!
【解决方案2】:

如果您坚持使用值类型方法(并且鉴于 identifier 不是唯一的:否则,请考虑使用字典进行简单的提取和替换逻辑),您可以为拥有的类型编写一个变异函数[Instruments] 数组,它在数组中找到(第一个)Instrument 实例,并使用提供的闭包对其进行变异。例如。 (感谢@Hamish 的改进!):

struct Instrument {
    let identifier: String
    var changeThis: Int
    init(_ identifier: String, _ changeThis: Int) {
        self.identifier = identifier
        self.changeThis = changeThis
    }
}

struct Foo {
    var instruments: [Instrument]

    @discardableResult // do not necessarily make use of the return result (no warning if not)
    mutating func updateInstrument(forFirst identifier: String,
            using mutate: (inout Instrument) -> ()) -> Bool {
        if let idx = instruments.indices
            .first(where: { instruments[$0].identifier == identifier }) {

            // mutate this instrument (in-place) using supplied closure
            mutate(&instruments[idx])

            return true // replacement successful
        }
        return false // didn't find such an instrument
    }
}

示例用法:

var foo = Foo(instruments:
    [Instrument("a", 1), Instrument("b", 2),
     Instrument("c", 3), Instrument("b", 4)])

// make use of result of call
if foo.updateInstrument(forFirst: "b", using: { $0.changeThis = 42 }) {
    print("Successfully mutated an instrument")
} // Successfully mutated an instrument

// just attempt mutate and discard the result
foo.updateInstrument(forFirst: "c", using: { $0.changeThis = 99 })

print(foo.instruments)
/* [Instrument(identifier: "a", changeThis: 1), 
    Instrument(identifier: "b", changeThis: 42), 
    Instrument(identifier: "c", changeThis: 99),
    Instrument(identifier: "b", changeThis: 4)] */

@Owen:s answer 所示,找到元素上某个谓词的第一个索引的更简洁的方法是使用数组的index(where:) 方法(而不是上面使用的indices.first(where:))。在上面的完整示例中使用index(where:) 方法只对应于替换

if let idx = instruments.indices
    .first(where: { instruments[$0].identifier == identifier }) { ...

if let idx = instruments
    .index(where: { $0.identifier == identifier }) { ...

FooupdateInstrument(forFirst:using)方法中。

我们可以进一步压缩updateInstrument(forFirst:using) 方法,通过应用Optionalmap 函数在一行中执行(可能的)替换和布尔返回:

struct Foo {
    var instruments: [Instrument]

    @discardableResult
    mutating func updateInstrument(forFirst identifier: String,
        using mutate: (inout Instrument) -> ()) -> Bool {
        return instruments
            .index(where: { $0.identifier == identifier })
            .map { mutate(&instruments[$0]) } != nil
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 2011-11-09
    • 2022-08-23
    • 2019-05-08
    相关资源
    最近更新 更多