Как вернуть словарь по ссылке в Swift?

#swift #swiftui #uikit

#swift #swiftui #uikit

Вопрос:

В следующем примере вы можете видеть, что словарь в экземпляре MyStruct не возвращается по ссылке в функции getDictionary(). Следовательно, любые изменения, внесенные в возвращаемый словарь, вносятся только в копию. Как вы можете вернуть словарь по ссылке?

  struct myStruct {
        func getDictionary() -> [Int:String] {
            return dictionary
        }
    
        private var dictionary = [1:"one"]
    
    }
    
    
    let c = myStruct()
    var sameDict = c.getDictionary()
    sameDict[2] = "two"
    
    print(c.getDictionary(), sameDict)
  

[1: «один»] [1: «один», 2: «два»]

Комментарии:

1. Вы можете сделать c.dictionary = ... или c.dictionary[2] = "two"

2. @pawello2222 конечно, но это не то, что я спрашивал

3. В соответствии с соглашением об именовании Swift ваши протоколы, структуры и классы называются с заглавной буквы.

4. Откуда вы знаете? И почему вы думаете inout , что это более «эффективно»? Даже с inout вы назначаете совершенно новый словарь каждый раз, когда вызываете этот метод.

5. Ну да, но Swift — это не C. Он не ведет себя как C, и ваш код не взаимодействует с C. Можно представить себе определенный вид «эффективности», но не касаясь реальности того, как работает Swift, независимо от того, используем ли мы inout или устанавливаем значение в словаре.

Ответ №1:

Словарь — это тип значения, это не ваш выбор, делать какой-либо тип структуры данных ссылкой или значением, это выбор Swift. В качестве ссылки могут использоваться только замыкание, класс и функции

В Swift массив, строка и словарьhttps://developer.apple.com/swift/blog/?id=10

Комментарии:

1. Значит, это тупик?

2. ДА. Они не могут быть использованы в качестве ссылки. Но на самом деле у вас есть абстрактная задача, которая вызывает like — я хочу сделать это как ссылку. В реальном приложении вам не нужно делать это со словарями

3. struct Типы @Rage могут передаваться по ссылке с помощью inout ключевого слова. Взгляните на мой ответ.

4. Его можно изменить как inout, но это не то же самое, что ссылка

5. Когда вы используете inout, то в начале функции у вас есть КОПИЯ глобальной переменной, после модификации этой копии внутри функции, перед возвратом, измененная копия БУДЕТ присвоена глобальной переменной. Это не изменение ссылки на переменную — это ПОЛНОЕ присвоение. (Надеюсь, вы поняли, что я пытаюсь сказать, извините за плохой английский)

Ответ №2:

Поскольку Dictionary это struct тип, единственный способ сделать это — передать его в функцию с помощью inout ключевого слова (указывает, что параметр будет изменен) следующим образом:

 struct MyStruct {
    func getDictionary() -> [Int: String] {
        return dictionary
    }
    
    mutating func updateDictionary(block: (inout [Int: String]) -> Void) {
        block(amp;dictionary)
    }

    private var dictionary = [1:"one"]
}


var c = MyStruct()
c.updateDictionary {
    $0[2] = "two"
}

print(c.getDictionary())
  

Обновление: После модификации копии внутри функции, перед возвратом, измененная копия БУДЕТ присвоена глобальной переменной. @AlexanderNikolaychuk и @matt указали на это в комментариях. Поведение можно увидеть, если запустить следующий код на игровой площадке:

 struct MyStruct {
    var some = 1
}

var myStruct = MyStruct() {
    didSet {
        print("didSet")
    }
}

func pass(something: inout MyStruct) {
    something.some = 2
    print("After change")
}

pass(something: amp;myStruct)
  

это выведет:

 After change
didSet
  

Просто говорю.

Комментарии:

1. В соответствии с соглашением об именовании Swift ваши протоколы, структуры и классы называются с заглавной буквы.

2. @LeoDabus вы абсолютно правы. Просто скопировал код из вопроса :). Обновление сейчас.

3. Как я уже сказал, это не ссылка в значении Swift, это присвоение новой измененной переменной старой глобальной )

4. @AlexanderNikolaychuk спасибо за знания. Я только что обновил свой ответ.

Ответ №3:

Похоже, вы не совсем поняли разницу между struct и class .

Когда вы инициализируете struct и назначаете его c , у вас есть его первая копия. Затем вы инициализируете новую переменную, вызывая ее sameDict и копируя в нее значение c dictionary . Затем вы изменяете вызываемую копию. sameDict Словарь c все тот же.

Проверьте этот документ:https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html

Stuct's передаются путем их копирования. classes получить ссылку.

Комментарии:

1. Я это полностью понимаю, я пытаюсь использовать функцию getDictionary для возврата словаря структуры по ссылке.

2. @Rage вам нужен NSDictionary (класс)