Ясный способ обновить вложенную структуру из большей структуры на месте - PullRequest
0 голосов
/ 13 марта 2019

Скажем, у нас есть некоторая сложная структура с несколькими вложенными уровнями (для простоты в примере будет только один уровень, но может быть и больше).

Пример.У нас есть структура данных:

struct Company {
    var employee: [Int: Employee]
}

struct Employee {
    var name: String
    var age: Int
}

var company = Company(employee: [
    1: Employee(name: "Makr", age: 25),
    2: Employee(name: "Lysa", age: 30),
    3: Employee(name: "John", age: 28)
    ])

Теперь мы хотим создать функцию, которая обновит некоторых сотрудников компании на месте.Мы могли бы написать это, используя inout param:

func setAge(_ age: Int, forEmployee employee: inout Employee) {
    employee.age = age  
}

setAge(26, forEmployee: &company.employees[1]!)

. Это работает, но, как вы можете видеть, нам нужно развернуть выражение 'company.employees [1]', прежде чем передать его в ref.Это принудительное развертывание может привести к ошибке времени выполнения, если для указанного ключа такого сотрудника нет.

Поэтому нам нужно проверить, существует ли сотрудник:

if company.employees[1] != nil {
    setAge(26, forEmployee: &company.employees[1]!)
}

Это также работает, но этот кодотчасти уродливо, потому что нам нужно повторить выражение «company.employees [1]» два раза.

Итак, вопрос: есть ли какой-нибудь способ избавиться от этого повторения?

Я попытался использовать необязательный параметр inout в функции изменения, но не смог заставить его работать.

Ответы [ 3 ]

1 голос
/ 13 марта 2019

Я бы просто добавил расширение к Employee, которое установит age

extension Employee {
    mutating func setAge(_ age: Int) {
        self.age = age
    }
}

сотрудника. Тогда вы можете использовать необязательную цепочку для вызовов.Поэтому, если значение для ключа 1 не существует, ничего не происходит, и код продолжается

company.employee[1]?.setAge(26)

Редактировать:

Если ваша цель - просто изменить какое-либо свойство, а затемвернуть объект, просто создать метод, который принимает необязательный параметр и возвращает необязательное значение

func setAge(_ age: Int, forEmployee employee: inout Employee?) -> Employee? {
    employee?.age = age
    return employee
}

if let employee = setAge(26, forEmployee: &company.employees[1]) { ... }
1 голос
/ 13 марта 2019

На основе ваших комментариев, как

В первую очередь я хотел иметь ссылку на подструктуру большей структуры, чтобы та часть кода, которая имеет дело с этой подструктурой, не могла ничего знать о том, где эта подструктура расположена в большей структуре.

и

Было бы идеально, если бы я мог просто создать локальный inout var. Как если бы var найм: inout Сотрудник? = company.employee [1] {// делаю все, что я хочу с этим сотрудником}.

Я думаю, что вам нужна общая функция обновления. В сообществе это часть семейства вспомогательных функций, именуемых with (https://forums.swift.org/t/circling-back-to-with/2766)

).

В этом случае вам нужна версия, которая в основном guard s на nil, поэтому я предлагаю что-то вроде

func performUpdateIfSome <T> (_ value: inout T?, update: (inout T) throws -> Void) rethrows {
  guard var _value = value else { return }
  try update(&_value)
  value = _value
}

с помощью этой утилиты то, что вы хотели сделать, будет сделано с

performUpdateIfSome(&company.employees[1], update: { $0.age = 26 })

Примечание

Если вы хотите абстрагироваться от , как получить доступ к сотруднику , но не company, тогда возможны также пути доступа:)

1 голос
/ 13 марта 2019

Вам необходимо скрыть реализацию и позволить структуре обрабатывать логику с помощью конкретной стратегии обработки ошибок, например, выдавать ошибку или просто возвращать истину / ложь в зависимости от успеха или просто игнорировать любые проблемы.Я не знаю, что означает ключ Int, но здесь я предполагаю, что это какой-то идентификатор, поэтому добавьте его в структуру компании

mutating func setAge(_ age: Int, forId id: Int) -> Bool {
    if employee.keys.contains(id) {
        employee[id]?.age = age
        return true
    }
    return false
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...