Возвращает значение из структуры при использовании - PullRequest
0 голосов
/ 17 мая 2018

Я довольно новичок в Swift и узнаю о struct s.Однако у меня есть проблема, которая может показаться очевидной, но я не уверен, как это сделать.Я делаю все это на детской площадке.

У меня есть struct с именем Colour, где я создаю цветовой тип RGB.Я хочу получить доступ к ее переменным (например, сделав yellow.red, который будет читать и записывать переменную, чтобы найти значение красного цвета в желтом цвете).

struct Colour {
    var red: Int
    var blue: Int
    var green: Int

    var rgb: [Int] // <- I don't want to have this variable, I want to make the struct Colour be this array

    init(red: Int, green: Int, blue: Int) {
        self.red = red
        self.green = green
        self.blue = blue

        rgb = [red, green, blue]
    }
}

Вызов:

let red = Colour(red: 255, green: 0, blue: 0) // Colour
red.red                                       // 255
red.green                                     // 0
red.blue                                      // 0

red                                           // Colour
red.rgb                                       // [255, 0, 0]

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

Так как я могу вызвать red и вернуть Array со значением [255, 0, 0]?

Примечания:

  • A get или set не может быть реализовано

  • Я не могу использовать Colour в качестве переменной, так как мне нужна инициализация

  • return ключевое слово не может быть использовано, так как struct s не работает таким образом

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

Извините за недостаточно четкое разъяснение.Я хотел вернуть [Int], но это явно не стоит того, что я пытался изначально.

Решения с протоколами определенно работают, если вы хотите вернуть строку, поэтому я принялответ.

Изменить 2

Теперь у нас есть рабочий ответ, используя type alias!

Ответы [ 5 ]

0 голосов
/ 18 мая 2018

Если вы хотите сделать тип Colour настраиваемой коллекцией, позволяя использовать его как Array, но в то же время сделать его безопасным для типов, вы можете создать пользовательский struct и привести его в соответствиедо Collection.Вы можете создать RGB enum, который можно использовать для индексации пользовательской коллекции, и отказавшийся инициализатор, который гарантирует, что вы можете создать только экземпляр Colour с действительными значениями RGB.

struct Colour: Collection, RandomAccessCollection {
    // Custom enum used for indexing Colour
    enum RGB: Int, Hashable, Comparable, Strideable {
        case red, green ,blue

        // Find the last existing rawValue, assumes that the first case has rawValue 0 and that rawValues are incremented by 1
        static let maxRawValue: RGB.RawValue = {
            var maxRawVal = 0
            while RGB(rawValue: maxRawVal) != nil {
                maxRawVal += 1
            }
            return maxRawVal
        }()

        static let rawValues: [RGB.RawValue] = {
            var rawValues = [RGB.RawValue]()
            var currentRawValue = 0
            while RGB(rawValue: currentRawValue) != nil {
                rawValues.append(currentRawValue)
                currentRawValue += 1
            }
            return rawValues
        }()

        static func <(lhs: RGB, rhs: RGB) -> Bool {
            return lhs.rawValue < rhs.rawValue
        }

        typealias Stride = Int
        func distance(to other: RGB) -> RGB.Stride {
            return self.rawValue - other.rawValue
        }

        func advanced(by n: RGB.Stride) -> RGB {
            return RGB(rawValue: (self.rawValue+n)%RGB.maxRawValue)!
        }
    }
    typealias Element = Int
    typealias Index = RGB

    //Private backing Array
    private var components:[Element] = Array<Element>.init(repeating: Element.init(), count: RGB.rawValues.count)
    var startIndex: Colour.Index {
        return RGB(rawValue: components.startIndex)!
    }
    var endIndex: Colour.Index {
        return RGB(rawValue: components.endIndex)!
    }

    subscript (position: Index) -> Element {
        get {
            return components[position.rawValue]
        }
        set {
            components[position.rawValue] = newValue
        }
    }

    func index(after i: Index) -> Index {
        return Index(rawValue: components.index(after: i.rawValue))!
    }
    private init(){}
    //Failable initializer that makes sure only a 3 element Array can be used as an input and that each element is in the valid RGB color code range
    init?<C:Collection>(_ collection:C) where C.Element == Element, C.Index == Index.RawValue {
        guard collection.indices.map({$0}) == RGB.rawValues else {return nil}
        for (index, element) in collection.enumerated() {
            guard element <= 255 && element >= 0 else {return nil}
            self.components[index] = element
        }
    }
}

Затем выможете безопасно использовать свою коллекцию:

let red = Colour([255,0,0]) // Colour
let invalidColour = Colour([255]) // nil
let invalidColour2 = Colour([255,2,3,4]) // nil
let invalidColour3 = Colour([255,-1,256]) // nil
let randomColour = Colour([1,5,231]) // Colour
// you can use the RGB cases to access the respective values in the collection
randomColour?[.red] // 1
0 голосов
/ 17 мая 2018

Я бы предложил добавить такую ​​функцию, как toArray()

, которая может выглядеть примерно так:

struct Colour {
  var red: Int
  var blue: Int
  var green: Int

  init(red: Int, green: Int, blue: Int) {
    self.red = red
    self.green = green
    self.blue = blue
  }

  func toArray() -> [Int] {
    return [self.red, self.green, self.blue]
  }
}

Затем в вашем коде вы можете просто использовать let rgbArray = MyColour.toArray()

Кроме того, я бы советовал не хранить одни и те же базовые данные дважды, например, с вашей переменной rgb.Если вы измените переменную Colour.red, это будет означать, что ваше значение Colour.rgb не будет автоматически обновлено этим новым значением, и вы неожиданно получите значения, которые вы не ожидали.С функциональным подходом у вас не будет этой проблемы.

0 голосов
/ 17 мая 2018

Swift имеет протокол под названием CustomDebugStringConvertible, который должен выполнить то, что вы ищете. После объявления, что ваша структура принимает этот протокол, просто внедрите переменную debugDescription в своем коде.

См. Код обновления:

struct Colour: CustomDebugStringConvertible {
    var red: Int
    var green: Int
    var blue: Int

    var debugDescription: String {
        return "\(array)"
    }

    var array: [Int] {
        return [red, green, blue]
    }

    init(red: Int, green: Int, blue: Int) {
        self.red = red
        self.green = green
        self.blue = blue
    }
}

Пример использования:

let red = Colour(red: 255, green: 0, blue: 0) // Colour
red.red                                       // 255
red.green                                     // 0
red.blue                                      // 0

red                                           // "[255, 0, 0]"
red.array                                     // [255, 0, 0]
0 голосов
/ 17 мая 2018

Кроме того, вы можете определить typealias Цвет. Это может быть немного более эффективным, но, возможно, не таким безопасным для типов.

См. Код:

typealias Colour = [Int]

extension Array where Element == Int {

    init(red: Int, green: Int, blue: Int) {
        self = [red, green, blue]
    }

    var red: Int { return self.count > 0 ? self[0] : 0 }
    var green: Int { return self.count > 1 ? self[1] : 0 }
    var blue: Int { return self.count > 2 ? self[2] : 0 }

}

Пример использования:

let red = Colour(red: 255, green: 0, blue: 0) // Colour
red.red                                       // 255
red.green                                     // 0
red.blue                                      // 0

red                                           // [255, 0, 0]
0 голосов
/ 17 мая 2018

red является Colour.Вы ничего не можете сделать, чтобы изменить это.Ничто из того, что вы делаете, не может заставить red действовать непосредственно как [Int], содержащий компоненты red, green и blue.

Есть разные вещи, которые вы можете сделать, в зависимости от того, что вы на самом делепотребности есть.Например, если вы просто хотите, чтобы он действовал как [Int] для печати, например [255, 0, 0], то вы можете переопределить var description: String и соответствовать CustomStringConvertible.

Тип функции, которую вы ищете, похож на пользовательские операторы преобразования C ++ .Это может быть действительно круто, но также может легко привести к очень нечеткому коду.Для ясности Swift предпочитает явно выражать такие преобразования.

...