【问题标题】:Introspect and iterate over static/computed properties in an enum内省和迭代枚举中的静态/计算属性
【发布时间】:2019-07-12 10:03:57
【问题描述】:

CaseIterable 协议允许您遍历枚举的情况,我想这样做,但对于静态属性,并获取它的值。你将如何实现理论上的PropertyIterable 协议?

我尝试过使用反射 (Mirror(reflecting:)),它适用于结构,但不适用于枚举

例如:

protocol PropertyIterable {
  var allProperties: [String: T] { get }  //will get you [String: Any/T]
}

仅供参考:可能计算属性 allProprties 未正确定义。但只是为了说明目的

enum Test: PropertyIterable {
  static let foo = "blah"
  static let bar = "blah2"
}


let test = Test.allProperties //will return ["foo": "blah", bar: "blah2"]

目前,当我打印 Mirror(describing: Test.self).children 时,我得到了这个:

AnyCollection<(label: Optional<String>, value: Any)>(_box: Swift._RandomAccessCollectionBox<Swift.LazyMapCollection<Swift.Range<Swift.Int>, (label: Swift.Optional<Swift.String>, value: Any)>>)

【问题讨论】:

  • 您看到的那种类型是一种惰性类型,它包装了Test 的值。由于大多数人只想迭代这些值,因此将它们复制到一个新的数组中是没有意义的。如果您需要,您可以使用Array(Mirror(describing: Test.self).children) 自己完成。但是随后,您会发现镜像不适用于这些自定义属性:(
  • @Alexander 我试过Array(Mirror(describing: Test.self).children),但我得到了一个空数组。那么,没有办法获取枚举中所有已定义属性的值吗?我想使用枚举来存储和组织常量。我从机器人娜塔莎那里得到了这个想法:natashatherobot.com/swift-enum-no-cases
  • 不,没有自动化的方法。充其量,您可以创建一个计算属性,该属性返回一个已手动列出的值的字典。
  • 你知道是否有提议实施类似的东西吗?或者为什么值得像 CaseIterable 那样获得案例而不是属性?
  • 编译器已经将此元数据烘焙到它构建的可执行文件中。调试器工具利用了这个元数据,但是没有 API(除了几乎没用的 Mirror)来访问它。他们还没有实施,因为它仍在经历很多变化。不过,这并没有阻止第三方对其进行逆向工程和实施反射库。请注意,随着这些实现细节在未来的 Swift 版本中发生变化,它们很容易被破坏。

标签: swift enums introspection swift-protocols


【解决方案1】:

如果我们使用CaseIterable,我们应该能够使用allCases.reduce 将其从[Test] 减少为[Test:String]

记得让你的枚举符合String,以便访问rawValue

protocol PropertyIterable: Hashable, CaseIterable {
    var rawValue: String { get }
    static var allProperties: [Self: String] { get }
}
extension PropertyIterable {
    static var allProperties: [Self: String] {
        allCases.reduce([Self:String]()) {
            var newValue = $0
            newValue[$1] = $1.rawValue
            return newValue
        }
    }
}

enum Test: String, PropertyIterable {
    case foo = "blah"
    case bar = "blah2"
}

let test = Test.allProperties
print(test) // prints: [Test.bar: "blah2", Test.foo: "blah"]

【讨论】:

  • 这不是作者要求的。他们想要遍历静态属性,而不是 case。
猜你喜欢
  • 2015-11-19
  • 2013-09-03
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
  • 1970-01-01
  • 2016-06-18
  • 1970-01-01
  • 2017-01-13
相关资源
最近更新 更多