#swift
Вопрос:
Я возвращаю экземпляр из подстрочного индекса, доступного только для получения, но не могу присвоить свойство возвращаемого экземпляра
struct Student { var id: String var attendance = 0 var absence = 0 } class StudentStore { var students = [Student]() subscript(id: String) -gt; Student? { students.first(where: { $0.id == id } ) } } var studentStore = StudentStore() var newStudent = Student(id: "2014901001") studentStore.students.append(newStudent) studentStore["2014901001"]?.attendance = 1 // error: Cannot assign to property: subscript is get-only
Комментарии:
1. Ну нет, потому
Student
что это структура и имеет семантику значения. Как насчет тогоStudent
, чтобы вместо этого провести занятие?
Ответ №1:
В подписке нет set
тер. То, что у вас есть, — это неявный get
тер, который является краткой формой
subscript(id: String) -gt; Student? { get { students.first(where: { $0.id == id } ) } }
Но в любом случае невозможно обновить элемент типа значения в массиве с помощью подписки на ключ.
Альтернативой является добавление функции обновления в магазин , которая принимает id
, a keyPath
и a value
func updateStudentlt;Valuegt;(withID id: String, keyPath: WritableKeyPathlt;Student,Valuegt;, value: Value) { guard let index = students.firstIndex(where: {$0.id == id}) else { return } students[index][keyPath: keyPath] = value }
Получение индекса обязательно для того, чтобы иметь возможность напрямую изменять элемент в массиве.
Затем вы можете заменить
studentStore["2014901001"]?.attendance = 1
с
studentStore.updateStudent(withID: "2014901001", keyPath: .attendance, value:1)
Комментарии:
1. Да, я забыл, что структура-это тип значения, но также нет необходимости в наборе в индексе, потому что я просто хочу получить экземпляр Student с помощью get, а затем назначить свойства экземпляра с помощью синтаксиса точек.
Ответ №2:
Когда вы это сделаете
studentStore["2014901001"]?.attendance = 1
Вы пытаетесь установить один из Student
объектов в students
массиве, не так ли?
Однако средство получения индексов не возвращает (ссылку на) один из объектов в students
массиве. Из-за семантики значений Student
структуры вы возвращаете копию Student
объекта, находящегося в students
массиве. Вы не сможете достичь того, чего хотите, если просто установите attendance
эту копию. Поэтому компилятор Swift компилирует ваш код примерно так:
let copy = studentStore["2014901001"] copy?.attendance = 1 studentStore["2014901001"] = copy
Вы можете видеть, что он снова устанавливает сеттер с измененной копией. Но в вашем индексе нет установщика, из-за чего возникает ошибка.
Чтобы решить эту проблему, вы можете создать Student
класс, который имеет ссылочную семантику. Это позволяет вам возвращать Student
объект, который находится в students
массиве, позволяя вызывающему подстрочному индексу устанавливать свою посещаемость.
class Student { var id: String var attendance = 0 var absence = 0 init(id: String, attendance: Int = 0, absence: Int = 0) { self.id = id self.attendance = attendance self.absence = absence } }
В качестве альтернативы вы можете добавить сеттера. Однако это позволило бы допустить подобную чепуху:
studentStore["1"] = Student(id: "2")
Вам нужно решить, что вы хотите, чтобы здесь произошло.
Комментарии:
1. Я забыл, что структура-это тип значения. Вместо этого я использовал класс, и это работает.
Ответ №3:
Ошибка показывает, что именно вам нужно изменить. Потому subcript
что вернется что-то подобное:
let updateStudent = studentStore["studentStore"]
Вы не можете измениться с
let
Так что обновите это:
if var updateStudent = studentStore["studentStore"] { updateStudent.attendance = 1 }
Комментарии:
1. Нет, из-за семантики значений это не обновит ученика в магазине. Вместо этого он обновит копию студента.
2. Да, ты прав. Я просто подумал, что он хочет исправить ошибку. Таким образом, потребуется еще один шаг для обновления
Student
объекта с заданным идентификатором.