Хранение объектов Generi c в гетерогенном массиве и получение параметра объекта в качестве правильного типа - PullRequest
1 голос
/ 28 апреля 2020

Привет всем,

Недавно я пытался реализовать систему графов на основе узлов, которая передает данные между узлами с помощью штекеров. Подобно многим 3D-приложениям, таким как houdini и maya.

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

Я застрял сейчас с массивами Swifts, так как я хотел бы сохранить список штекеров Generi c. Каждый плагин может иметь свой собственный тип значений float, int, color, string, Vector Matrix.

Я прочитал о Type Erasers и непрозрачных типах, но все еще не могу получить мои значения нашего списка в способ, которым я могу выполнить некоторую арифметику c над ними.

Все и любая помощь, которая может направить меня в этом направлении, будет принята с благодарностью: D

import Foundation
import MetalKit

protocol genericPlug {
    associatedtype T
    func GetValue() -> T
}


class Plug<T>:genericPlug{
    var _value:T?
    var value:T {
        get{GetValue()}
        set(val){
            value = val
        }
    }

    func GetValue() -> T{
        return _value!
    }

    init(_ newValue:T){
        _value=newValue
    }
}

class Node{
    var plugs:[genericPlug] = []
    init(){
        var p1 = Plug<Int>(0)
        var p2 = Plug(vector2(1.2, 3.1))
        var p3 = Plug([0.0, 3.1, 0.6, 1])

        plugs.append(p1)
        plugs.append(p2)
        plugs.append(p3)
    }

    func execute(){
        // will access the plugs in the array and perform some sort of calculations on them.
        plugs[0].value + 1      // should equal 1
        plugs[1].value.x + 0.8  // should have x=2.0 y=3.1
        plugs[2].value[1] - 0.1 // should equal 3.0
    }
}

Спасибо всем

Ответы [ 2 ]

0 голосов
/ 04 мая 2020

Используйте универсальный c что-то, чтобы извлечь то, что вам нужно. Ваши параметры - это методы и подписки.

protocol PlugValue {
  init()
}

extension Int: PlugValue { }
extension Float: PlugValue { }
extension Double: PlugValue { }
extension SIMD3: PlugValue where Scalar == Int32 { }
struct Plug<Value: PlugValue> {
  var value: Value

  init(_ value: Value) {
    self.value = value
  }
}
protocol AnyPlug {
  var anyValue: PlugValue { get }
}

extension AnyPlug {
  subscript<Value: PlugValue>(type: Value.Type = Value.self) -> Value {
    anyValue as? Value ?? .init()
  }

  func callAsFunction<Value: PlugValue>(_ type: Value.Type = Value.self) -> Value {
    anyValue as? Value ?? .init()
  }
}

extension Plug: AnyPlug {
  var anyValue: PlugValue { value }
}
let plugs: [AnyPlug] = [
  Plug(1),
  Plug(2.3 as Float),
  Plug(4.5),
  Plug([6, 7, 8] as SIMD3)
]

plugs[0][Int.self] // 1
plugs[1][Double.self] // 0
plugs[1][] as Float // 2.3
let double: Double = plugs[2]() // 4.5
plugs[3](SIMD3.self).y // 7

С массивом протоколов, вам нужно бросить их в свой Plug при получении каждый раз?

По существу. Это верно для всех гетерогенных последовательностей. Вот ваши варианты:

extension Array: PlugValue where Element: PlugValue { }

let plug: AnyPlug = Plug([0.1, 1.1, 2.1])
(plug as? Plug<[Double]>)?.value[1]
(plug.anyValue as? [Double])?[1]
extension Plug {
  enum Error: Swift.Error {
    case typeMismatch
  }
}

extension AnyPlug {
  func callAsFunction<Value: PlugValue, Return>(_ closure: (Value) -> Return) throws {
    guard let value = anyValue as? Value
    else { throw Plug<Value>.Error.typeMismatch }

    closure(value)
  }
}

try plug { (doubles: [Double]) in doubles[1] } // 1.1
try plug { ($0 as [Double])[1] } // 1.1
try plug { $0 as Int } // <Swift.Int>.Error.typeMismatch
0 голосов
/ 04 мая 2020

Мне удалось найти решение, которое работало бы для моих нужд.

Я все еще ищу способ улучшить получение данных и их правильный тип.

import Foundation
import MetalKit

// Creating the PlugType Enum
enum PlugType{
    case Integer(Int?)
    case Float_(Float?)
    case Double_(Double?)
    case Vector3(simd_int3)

    // default types
    static func IntegerType() -> PlugType{ return PlugType.Integer(nil)}
    static func FloatType() -> PlugType{ return PlugType.Float_(nil)}
    static func DoubleType() -> PlugType{ return PlugType.Double_(nil)}
}

// Implements a way to retrieve the correct value type
extension PlugType{
    var IntegerValue: Int{
        switch self{
            case .Integer(let value):
                return value ?? 0
            default:
                return 0
        }
    }

    var FloatValue: Float{
        switch self
        {
        case .Float_(let value):
            return value ?? 0
        default:
            return 0
        }
    }

    var DoubleValue: Double{
        switch self
        {
        case .Double_(let value):
            return value ?? 0
        default:
            return 0
        }
    }
}

// Get the string representation of the PlugType
extension PlugType {
    var typeName: String{
        switch self {
        case .Integer: return "Integer"
        case .Float_: return "Float"
        case .Double_: return "Double"
        case .Vector3: return "Vector3"
        }
    }

    var swiftType: Any.Type {
        switch self {
        case .Integer: return Int.self
        case .Float_: return Float.self
        case .Double_: return Double.self
        case .Vector3: return simd_int3.self
        }
    }
}

class Plug{
    var _value:PlugType?
    var type:String? { get{ return _value?.typeName } }

    init(_ newValue:PlugType){
        _value = newValue
    }

    func geee<T>(_ input:T) -> T{
        switch type {
            case "Integer":
                return getVal(_value!.IntegerValue) as! T
            case "Double":
                return getVal(_value!.DoubleValue) as! T
            default:
            return 0 as! T
        }

    }

    func getVal(_ val:Int) -> Int {
        return val
    }
    func getVal(_ val:Float) -> Float {
        return val
    }
    func getVal(_ val:Double) -> Double {
        return val
    }
}

var plugs:[Plug] = []
var p1 = Plug(PlugType.Integer(2))
...