swift – 如何扩展float3或任何其他内置类型以符合Codable协议?
发布时间:2020-12-14 04:52:12 所属栏目:百科 来源:网络整理
导读:在尝试使用基本 JSONEncoder序列化float3对象数组时,发现float3不符合Codable协议,因此无法完成. 我尝试按照下面的建议编写一个基本扩展,如下所示,但是在初始化所有存储属性之前使用的错误’self’是为init中的每个赋值行呈现的.我假设这是因为编译器不确定F
在尝试使用基本
JSONEncoder序列化float3对象数组时,发现float3不符合Codable协议,因此无法完成.
我尝试按照下面的建议编写一个基本扩展,如下所示,但是在初始化所有存储属性之前使用的错误’self’是为init中的每个赋值行呈现的.我假设这是因为编译器不确定Float.self是否在float3初始化之前定义,但我不知道如何解决这个问题. 此外,init的结尾表示从初始化器返回而没有初始化所有存储的属性,我假设除了x,y和z之外还有float3属性,但是我想知道是否有办法默认/忽略这些属性,和/或如何找到完整的属性列表,而不是挖掘simd中的所有float3扩展. 如果您对如何做到这一点有任何想法,那么分享它们将非常感激.谢谢! import SceneKit extension float3: Codable { public init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) x = try values.decode(Float.self,forKey: .x) y = try values.decode(Float.self,forKey: .y) z = try values.decode(Float.self,forKey: .z) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(x,forKey: .x) try container.encode(y,forKey: .y) try container.encode(z,forKey: .z) } enum CodingKeys: String,CodingKey { case x case y case z } } 这是simd文件中的(我认为完整的)float3定义: /// A vector of three `Float`. This corresponds to the C and /// Obj-C type `vector_float3` and the C++ type `simd::float3`. public struct float3 { public var x: Float public var y: Float public var z: Float /// Initialize to the zero vector. public init() /// Initialize a vector with the specified elements. public init(_ x: Float,_ y: Float,_ z: Float) /// Initialize a vector with the specified elements. public init(x: Float,y: Float,z: Float) /// Initialize to a vector with all elements equal to `scalar`. public init(_ scalar: Float) /// Initialize to a vector with elements taken from `array`. /// /// - Precondition: `array` must have exactly three elements. public init(_ array: [Float]) /// Access individual elements of the vector via subscript. public subscript(index: Int) -> Float } extension float3 : Equatable { /// True iff every element of lhs is equal to the corresponding element of /// rhs. public static func ==(lhs: float3,rhs: float3) -> Bool } extension float3 : CustomDebugStringConvertible { /// Debug string representation public var debugDescription: String { get } } extension float3 : ExpressibleByArrayLiteral { /// Initialize using `arrayLiteral`. /// /// - Precondition: the array literal must exactly three /// elements. public init(arrayLiteral elements: Float...) } extension float3 : Collection { /// The position of the first element in a nonempty collection. /// /// If the collection is empty,`startIndex` is equal to `endIndex`. public var startIndex: Int { get } /// The collection's "past the end" position---that is,the position one /// greater than the last valid subscript argument. /// /// When you need a range that includes the last element of a collection,use /// the half-open range operator (`..<`) with `endIndex`. The `..<` operator /// creates a range that doesn't include the upper bound,so it's always /// safe to use with `endIndex`. For example: /// /// let numbers = [10,20,30,40,50] /// if let index = numbers.index(of: 30) { /// print(numbers[index ..< numbers.endIndex]) /// } /// // Prints "[30,50]" /// /// If the collection is empty,`endIndex` is equal to `startIndex`. public var endIndex: Int { get } /// Returns the position immediately after the given index. /// /// The successor of an index must be well defined. For an index `i` into a /// collection `c`,calling `c.index(after: i)` returns the same index every /// time. /// /// - Parameter i: A valid index of the collection. `i` must be less than /// `endIndex`. /// - Returns: The index value immediately after `i`. public func index(after i: Int) -> Int } extension float3 { /// Vector (elementwise) sum of `lhs` and `rhs`. public static func +(lhs: float3,rhs: float3) -> float3 /// Vector (elementwise) difference of `lhs` and `rhs`. public static func -(lhs: float3,rhs: float3) -> float3 /// Negation of `rhs`. prefix public static func -(rhs: float3) -> float3 /// Elementwise product of `lhs` and `rhs` (A.k.a. the Hadamard or Schur /// vector product). public static func *(lhs: float3,rhs: float3) -> float3 /// Scalar-Vector product. public static func *(lhs: Float,rhs: float3) -> float3 /// Scalar-Vector product. public static func *(lhs: float3,rhs: Float) -> float3 /// Elementwise quotient of `lhs` and `rhs`. public static func /(lhs: float3,rhs: float3) -> float3 /// Divide vector by scalar. public static func /(lhs: float3,rhs: Float) -> float3 /// Add `rhs` to `lhs`. public static func +=(lhs: inout float3,rhs: float3) /// Subtract `rhs` from `lhs`. public static func -=(lhs: inout float3,rhs: float3) /// Multiply `lhs` by `rhs` (elementwise). public static func *=(lhs: inout float3,rhs: float3) /// Divide `lhs` by `rhs` (elementwise). public static func /=(lhs: inout float3,rhs: float3) /// Scales `lhs` by `rhs`. public static func *=(lhs: inout float3,rhs: Float) /// Scales `lhs` by `1/rhs`. public static func /=(lhs: inout float3,rhs: Float) } 解决方法
您可以解决编译器错误,而不是尝试直接将解码值分配给您的类型的字段,将解码的值存储在局部变量中,然后调用指定的初始化器float3.
正如Rob在his answer中提到的那样,问题的原因与x,y和z是计算属性而不是存储属性有关,因此在初始化期间不能直接写入它们. extension float3: Codable { public init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) let x = try values.decode(Float.self,forKey: .x) let y = try values.decode(Float.self,forKey: .y) let z = try values.decode(Float.self,forKey: .z) self.init(x,y,z) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(x,forKey: .z) } private enum CodingKeys: String,CodingKey { case x,z } } 您可以使用以下代码在Playground中测试编码和解码: let vector = float3(3,2.4,1) do { let encodedVector = try JSONEncoder().encode(vector) let jsonVector = String(data: encodedVector,encoding: .utf8) //"{"x":3,"y":2.4000000953674316,"z":1}" let decodedVector = try JSONDecoder().decode(float3.self,from: encodedVector) //float3(3.0,1.0) } catch { print(error) } 如果您更喜欢更简洁的代码,init(来自解码器:)方法可以缩短为: public init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) try self.init(values.decode(Float.self,forKey: .x),values.decode(Float.self,forKey: .y),forKey: .z)) } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |