【问题标题】:Cannot assign to immutable expression of type Swift无法分配给 Swift 类型的不可变表达式
【发布时间】:2017-07-14 14:27:31
【问题描述】:

我在没有太多帮助的情况下看到了几个类似的 SO 问题,

我正在尝试使用 timesArray 函数 updateDailyTimes 更新星期一的 availabilityTimes

availabilityTimestimesArray 的示例

 var availabilityTimes = [
         "Monday": [ "available" : true,
                     "times": [
                         ["startTime": "9:00 am", "endTime": "1:30 pm" ],
                         ["startTime": "2:30 pm", "endTime": "6:00 pm" ],
                         ["startTime": "7:30 pm", "endTime": "9:00 pm" ]
                     ]
         ],
         "Tuesday": [ "available" : true,
                     "times": [
                         ["startTime": "9:00 am", "endTime": "6:00 pm" ]
                     ]
                    ]
          ]




var timesArray = [
                    ["startTime": "9:00 am", "endTime": "1:30 pm" ],
                    ["startTime": "2:30 pm", "endTime": "6:00 pm" ],
                    ["startTime": "7:30 pm", "endTime": "9:00 pm" ]
                  ]

这是我的代码,当我调用下面的函数时,我在代码行value["times"] as [[String : String]] = timesArray 中收到错误消息cannot assign to immutable expression of type [[String : String]]

func updateDailyTimes(day: String, timesArray: [[String:String]]){

    guard var updatedTimes = self.availabilityTimes as? [String: AnyObject] else{
        return
    }

    for (key, var value) in updatedTimes {

        if key == day{
            for (key1, value1) in value as! [String : AnyObject]{
                if key1 as String == "times" {
                    value["times"] as [[String : String]] = timesArray // I get an error message in this line
                }
            }

        }
    }
}

【问题讨论】:

  • 您正在与具有值语义的 Swift 集合类型作斗争。使用自定义结构或类。它让生活更轻松。
  • @vadian,如果你能详细说明会很棒。

标签: swift


【解决方案1】:

根据我的评论,我的意思是一个自定义结构 Times 用于开始和结束时间,一个结构 DailyTimes 具有所需的属性和一个变异函数来更新 Times 数组:

struct Times {
    let start : String
    let end : String
}

struct DailyTimes {
    let weekday : String
    var available : Bool
    var times = [Times]()

    mutating func update(times : [Times]) {
        self.times = times
    }
}

现在创建availableTimes 字典:

var availableTimes = ["Monday" : DailyTimes(weekday: "Monday", available: true, times: [Times(start: "9:00 am", end:"1:30 pm"),
                                                                                        Times(start: "2:30 pm", end:"6:00 pm"),
                                                                                        Times(start: "7:30 pm", end:"9:00 pm")]),
                      "Tuesday" : DailyTimes(weekday: "Tuesday", available: true, times: [Times(start: "9:00 am", end:"6:00 pm")])]

还有timesArray 数组:

let timesArray = [Times(start: "9:00 am", end:"1:30 pm"),
                  Times(start: "2:30 pm", end:"6:00 pm"),
                  Times(start: "7:30 pm", end:"9:00 pm")]

由于MondayTimes 数组已经包含timesArray 的值,让我们更新Tuesday

availableTimes["Tuesday"]?.update(times:timesArray)

终于证明了

print(availableTimes["Tuesday"]?.times)

另一个改进可能是使用 DateComponents 而不是 Strings 的时代。

【讨论】:

  • 谢谢你的详细解释,我会接受你的建议。
【解决方案2】:

在 Swift 中,Dictionary 是一个结构体,它是一个值类型。将值类型想象成基本类型,例如 int

如果你有这个:

int a = 0
int b = a

然后b得到a的值,它们不相同。

因此,当您遍历字典时,您的 (key, value) 对实际上并不是字典中的内容,它们只是具有相同的值。在迭代值或引用时不要改变它也很重要。这可能会导致奇怪的错误。

enum AvailabilityTimeMarker {
    case start
    case end
}
enum DayOfTheWeek: String {
    case monday = "Monday"
    case tuesday = "Tuesday"
    case wednesday = "Wednesday"
    case thursday = "Thursday"
    case friday = "Friday"
    case saturday = "Saturday"
    case sunday = "Sunday"
}

typealias Availability = [DayOfTheWeek : AvailabilityDay]
typealias AvailabilityDay = [String : Any]
typealias AvailabilityArray = [AvailabilityTime]
typealias AvailabilityTime = [AvailabilityTimeMarker : String]

var availabilityTimes: Availability = [
    .monday : [ "available" : true,
                "times": [
                    ["startTime": "9:00 am", "endTime": "1:30 pm" ],
                    ["startTime": "2:30 pm", "endTime": "6:00 pm" ],
                    ["startTime": "7:30 pm", "endTime": "9:00 pm" ]
        ]
    ],
    .tuesday : [ "available" : true,
                 "times": [
                    ["startTime": "9:00 am", "endTime": "6:00 pm" ]
        ]
    ]
]

var timesArray: AvailabilityArray = [
    [.start : "9:00 am", .end : "1:30 pm" ],
    [.start : "2:30 pm", .end : "6:00 pm" ],
    [.start : "7:30 pm", .end : "9:00 pm" ]
]

func updateDailyTimes(day: DayOfTheWeek, timesArray: AvailabilityArray) {

    let availabilities = self.availabilityTimes

    var newtimes = availabilities

    if var newDayAvailability = availabilities[day] {
        newDayAvailability["times"] = newtimes

        newtimes[day] = newDayAvailability

        self.availabilityTimes = newtimes// Since we're not using reference semantics, we have to change the entire value
    }
}

【讨论】:

  • 感谢您的明确解释。由于我想更新特定日期的时间,所以 newtimes[key1] = timesArray as AnyObject 应该是 newtimes[day][key1] = timesArray as AnyObject 吗? .当我尝试newtimes[day][key1] 我得到类似的错误cannot assign to immutable expression of type Any
  • 正如@vadian 提到的,当正确的解决方案可能是创建自己的结构来包装一些字典或使用类来获得引用语义的好处时,我们正在与价值语义作斗争。如果你来自 objc,你也可以直接使用NSDictionary 来获取引用语义,但是你会失去类型安全。
  • @user44776,我上次更新了代码,完全重写显示了一种更简单的方法。我还使用了一些 Swift 特性来让一切变得更加清晰。
  • 感谢详细的代码,我去了@vadian 回答,因为它更容易理解。
  • @user44776 他的回答绝对是真正实现代码的正确方法。我个人会这样做,我只是想帮助你理解引用类型,因为你会在 Swift 中经常遇到它们。
猜你喜欢
  • 2015-11-12
  • 2016-08-02
  • 2017-05-16
  • 2017-04-14
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2019-10-30
  • 1970-01-01
相关资源
最近更新 更多