Как можно избежать повторения операции доступа к индексу массива в том же массиве элемента структуры? - PullRequest
1 голос
/ 06 июля 2019

Рассмотрим следующий код:

struct Card {
    var name0: String
    var name1: String
}

var cards = [Card]()
cards.append(Card(name0: "hello", name1: "world"))

// Need to perform array index access, 
// every time I want to mutate a struct property :(
cards[0].name0 = "good"
cards[0].name1 = "bye"
// ...
// ...

// "good bye"
print(cards[0].name0 + " " + cards[0].name1)

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

// Ok. This is an invalid Swift statement.
var referenceToCardStruct = &(cards[0])

referenceToCardStruct.name0 = "good"
referenceToCardStruct.name1 = "bye"
// ...
// ...

Ответы [ 5 ]

3 голосов
/ 06 июля 2019

Здесь много хороших ответов, и вы не должны думать о типах значений как о «ограничении». Поведение типов значений очень преднамеренное и является важной особенностью. Как правило, я бы рекомендовал inout для этой проблемы, как предполагает Мэтт.

Но также возможно получить синтаксис, который вы описываете. Вам просто нужна вычисляемая переменная (которая может быть локальной).

let index = 0 // Just to show it can be externally configurable

var referenceToCardStruct: Card {
    get { cards[index] }
    set { cards[index] = newValue }
}
referenceToCardStruct.name0 = "good"
referenceToCardStruct.name1 = "bye"

print(cards[0].name0 + " " + cards[0].name1)
3 голосов
/ 06 июля 2019
struct Card {
    var name0: String
    var name1: String
}

var cards = [Card]()

// every time I want to mutate a struct property :(
cards[0].name0 = "good"
cards[0].name1 = "bye"

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

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

Если вы не хотите видеть повторное использование индекса, вы можете скрыть его в функции, используя inout:

func mutate(card: inout Card) {
    card.name0 = "good"
    card.name1 = "bye"
}
for index in cards.indices {
    mutate(card:&cards[index])
}

Однажды Swift может включать for inout, что позволит вам циклически проходить по массиву struct и мутировать каждый экземпляр структуры напрямую. Но этот день еще не здесь.

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

2 голосов
/ 06 июля 2019

Если вы не хотите повторять индекс, создайте переменную из значения, которое вы хотите.

var cards = [Card]()
cards.append(Card(name0: "hello", name1: "world"))

var card = cards[0]
card.name0 = "good"
card.name1 = "bye"
// ...
// ...
cards[0] = card // update the array with the updated card

// "good bye"
print(card.name0 + " " + card.name1)
2 голосов
/ 06 июля 2019

struct - это тип значения, вы не можете получить ссылку на его объект с присваиванием, вы должны пойти по этому пути, использовать мутирующий метод, такой как https://stackoverflow.com/a/52497495/5820010 или использовать class вместо

1 голос
/ 06 июля 2019

Я думаю, что метод мутации - это путь, на который указывает Ш_Кхан.

В вашем случае я бы сделал что-то вроде:

  1> struct Card { 
  2.     var name0: String 
  3.     var name1: String 
  4. } 
  5.  
  6. var cards = [Card]()
  7. cards.append(Card(name0: "hello", name1: "world")) 
cards: [Card] = 1 value {
  [0] = {
    name0 = "hello"
    name1 = "world"
  }
}
  8> extension Card { 
  9.     mutating func setNames(name0: String, name1: String) { 
 10.         self.name0 = name0
 11.         self.name1 = name1 
 12.     } 
 13. } 
 14> cards[0].setNames(name0: "x", name1: "y") 
 15> cards
$R0: [Card] = 1 value {
  [0] = {
    name0 = "x"
    name1 = "y"
  }
}

Другой подход - это оптовое обновление cards[0].

В некотором роде вы хотите использовать синтаксис обновления записей (например, Haskell или Elm) или словарь с функциональностью слияния. Но посмотрите на светлую сторону. Может быть, отсутствие у Swift такой простоты является свидетельством того, что он имеет мутацию static-typing-and-value-semantics-while-allow-mutation, и эта комбинация функций, я думаю, заставляет мутирующий функционал или элемент полного массива обновлять почти все, кроме требуется. Я не уверен, что в Swift есть синтаксическая функция для обновления нескольких свойств за один снимок (без написания собственной функции или метода).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...