Как вставить элемент другого типа в массив

У меня есть class со ссылкой на другой class. У студенческого класса есть переменная со ссылкой на информацию о модуле. Я хочу вставить moduleId в массив, но структура состоит из разных типов объектов и имеет тип moduleRef. Я хотел бы получить moduleId типа string. Как я могу получить этот элемент moduleId из формы ModuleRef.

class Student {
    var firstName: String
    var lastName: String
    var modulesRefs: [ModuleRef]

    var fullName: String {
        return self.firstName + " " + self.lastName
    }

    init(firstName: String, lastName: String, modulesRefs: [ModuleRef]) {
        self.firstName = firstName
        self.lastName = lastName
        self.modulesRefs = modulesRefs
    }

    func addModuleId(_ moduleId: String) {
        self.modulesRefs.insert(moduleId, at: 0)
    }

     func removeModuleId(_ moduleId: String) {
        self.modulesRefs = self.modulesRefs.filter { $0.moduleId != moduleId }
    }
}

class ModuleRef {
    var moduleName: String
    var moduleId: String
    var moduleStartdate: Int

    init(moduleName: String, moduleId: String, moduleStartdate: Int) {
        self.moduleName = moduleName
        self.moduleId = moduleId
        self.moduleStartdate = moduleStartdate
    }
}

Cannot convert value of type 'String' to expected argument type 'ModuleRef'

Можете ли вы показать метод вставки?

Sohil R. Memon 28.01.2019 13:00

@SohilR.Memon insert находится в Swift's standard library

mandem112 28.01.2019 13:02

Вы звоните addModuleId, чтобы вставить новое значение?

Sohil R. Memon 28.01.2019 13:03

@SohilR.Memon да. Что такое строка

mandem112 28.01.2019 13:03

как насчет moduleName и moduleStartdate, когда вы передаете только moduleId, каково будет значение этих двух переменных?

Sohil R. Memon 28.01.2019 13:04

@SohilR.Memon Я не использую ни один из них на данный момент

mandem112 28.01.2019 13:05

хорошо, тогда это может быть nil? Поскольку в названии class "ModuleRef" вы сделали их обязательными.

Sohil R. Memon 28.01.2019 13:06

@SohilR.Memon Я, наверное, могу это изменить

mandem112 28.01.2019 13:06

Да, вы можете сделать это nil или вы можете просто передать значение по умолчанию, например пустую строку и значение 0, что вы скажете?

Sohil R. Memon 28.01.2019 13:07

Проверьте ответ!

Sohil R. Memon 28.01.2019 13:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
88
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Вам нужно сделать массив типа Any..

var modulesRefs: [Any] = []

Вы можете добавить элемент в массив следующим образом...

modulesRefs.append("Test string")
let obj = ModuleRef(...)
modulesRefs.append(obj)

И когда вы получаете доступ к элементу, вам нужно использовать либо if let, либо guard let, чтобы безопасно проверить его тип.

Например.

  for obj in modulesRefs {
    if let strType = obj as? String {
       print("\(obj) is string type")
    } else if let moduleRefObj = obj as? ModuleRef {
       print("\(obj) is ModuleRef type")
  }
Не надо использует Any. Всего для двух разных типов используется общий протокол.
vadian 28.01.2019 13:12

Вам необходимо обновить тип массива до Any следующим образом:

var modulesRefs: [Any] 

При доступе к значению из массива,

if let moduleRef = modulesRefs[index] as? ModuleRef {

} else if let str = modulesRefs[index] as? String  {

}
Не надо использует Any. Всего для двух разных типов используется общий протокол.
vadian 28.01.2019 13:12

@vadian это также смутило меня, зачем мне пытаться получить moduleId из другого класса

mandem112 28.01.2019 13:13

В своем коде вы сделали значения class ModuleRef { ... } обязательными, и вы просто передаете одно значение moduleId и добавляете его к Array из ModuleRef, что является совершенно неправильным подходом. Итак, на основании того, что вы сказали, это обновленный код вашего кода:

class Student {
    var firstName: String
    var lastName: String
    var modulesRefs: [ModuleRef]

    var fullName: String {
        return self.firstName + " " + self.lastName
    }

    init(firstName: String, lastName: String, modulesRefs: [ModuleRef]) {
        self.firstName = firstName
        self.lastName = lastName
        self.modulesRefs = modulesRefs
    }

    func addModuleId(_ moduleId: String) {
        // This will be your updated intializer where you can pass any value you want and other will be taken as default value
        let moduleRef = ModuleRef(moduleId: moduleId)
        self.modulesRefs.insert(moduleRef, at: 0)
    }

    func removeModuleId(_ moduleId: String) {
        self.modulesRefs = self.modulesRefs.filter { $0.moduleId != moduleId }
    }
}

class ModuleRef {
    var moduleName: String
    var moduleId: String
    var moduleStartdate: Int

    /// Here you can provide all the default values which you don't want to pass
    init(moduleName: String = "", moduleId: String = "", moduleStartdate: Int = 0) {
        self.moduleName = moduleName
        self.moduleId = moduleId
        self.moduleStartdate = moduleStartdate
    }
}

Кроме того, вы также можете передать значение nil для всех, создавая переменную как optional. Дайте мне знать, если у вас есть путаница!

Вы не можете вставить ModuleRef, просто передав String.

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

func addModuleId(_ moduleId: String) {
    let moduleRef = ModuleRef(moduleName: self.fullName, 
                              moduleId: moduleId, 
                              moduleStartDate: Int(Date().timeIntervalSince1970))
    self.modulesRefs.insert(moduleRef, at: 0)
}

И для удаления объекта это более эффективно, однако класс должен соответствовать Equatable

func removeModuleId(_ moduleId: String) {
    guard let index = self.modulesRefs.firstIndex(where: {$0.moduleId == moduleId}) else { return }
    self.modulesRefs.remove(at: index)
}

Я бы даже объявил moduleStartDate как Date.

это здорово, но что, если я просто хочу, чтобы moduleId был в объекте moduleRef. Как я могу это сделать. Я не могу просто исключить их. Выдаст мне ошибку с сообщением invalid number of arguments?

mandem112 28.01.2019 13:26

Что именно вы собираетесь выполнить с помощью метода addModuleId? Учтите, что массив modulesRefs содержит несколько объектов ModuleRef, которые имеют 3 свойства соответственно.

vadian 28.01.2019 13:28

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

mandem112 28.01.2019 13:32
Ответ принят как подходящий

Вы можете вставить значения Type ModuleRef в этот массив. Поэтому я могу изменить функции как:

func addModuleId(_ moduleId: String) {
        let module = ModuleRef(moduleName: "", moduleId: moduleId, moduleStartdate: 0)
        self.modulesRefs.insert(module, at: 0)
    }

    func removeModuleId(_ moduleId: String) {
        modulesRefs.removeAll(where: { $0.moduleId == moduleId })
    }

NB: Если вам не нужны moduleName и moduleStartdate все время, вы можете пометить их как необязательные.

То, что вы пытаетесь сделать, на самом деле означает, что в вашем дизайне есть изъян.

Если вам нужна функциональность для вызова student.addModuleId(moduleId), это означает, что Student не должен содержать массив ModuleRef. (Или, по крайней мере, иметь механизм для извлечения всего ModuleRef по его идентификатору, а затем вставлять этот ModuleRef внутрь массива)

При этом после выяснения вашего дизайна, для которого он будет: modules: [ModuleRef] или moduleIds: [String], есть еще кое-что, что вы можете использовать:

Протокол Equatable. Если вы сделаете ModuleRef соответствующим протоколу Equatable и проверите его равенство с id, то Swift предоставит вам доступ к методу remove(element:_), и метод removeModuleId() вам больше не понадобится.

Или, если все ModuleId уникальны, вы также можете реализовать протокол Hashable и использовать Set<ModuleRef> вместо массива, чтобы иметь методы удаления и вставки O (1). (прямо сейчас удалите функцию, занимает O(n) времени)

Другие вопросы по теме