是否可以在Swift Collection上流产地图功能



我们有一个情况下,我们需要将Array<Any>类型的对象转换为Array<Codable>。如果原始数组中的任何项目都不遵守 Codable,那么我们希望整个东西都流产并返回nil。

或当前的方法是手动循环循环所有内容,一路上测试,就像这样...

func makeCodable(sourceArray:Array<Any>) -> Array<Codable>?{
    var codableArray = Array<Codable>()
    for item in sourceArray{
        guard let codableItem = item as? Codable else {
            return nil
        }
        codableArray.append(codableItem)
    }
    return codableArray
}

但是,我想知道是否有一种更简单的方法可以使用map命令来执行此操作,但是如果无法映射任何元素,它将要求它短路。这就是我不确定的。

例如,此伪代码...

func makeCodable(sourceArray:Array<Any>) -> Array<Codable>?{
    return sourceArray.map({ $0 as? Codable});
}

这是可能的,还是我们的原始方式正确/唯一的方法?

这是一种使用mapthrows的解决方案。

func makeCodable(sourceArray: [Any]) -> [Codable]? {
    enum CodableError: Error {
        case notCodable
    }
    let res: [Codable]? = try? sourceArray.map {
        guard let codable = $0 as? Codable else {
            throw CodableError.notCodable
        }
        return codable
    }
    return res
}
let res = makeCodable2(sourceArray: [5, 6.5, "Hi", UIView()])
print(res) // nil

这是一种变体,可以使makeCodable投掷并返回非选项数组:

enum CodableError: Error {
    case notCodable
}
func makeCodable(sourceArray: [Any]) throws -> [Codable] {
    let res: [Codable] = try sourceArray.map {
        guard let cod = $0 as? Codable else {
            throw CodableError.notCodable
        }
        return cod
    }
    return res
}
do {
    let res = try makeCodable(sourceArray: [5, 6.5, "Hi"])
    print(res) // prints array
    let bad = try makeCodable(sourceArray: [5, 6.5, "Hi", UIView()])
    print(bad)
} catch {
    print(error) // goes here on 2nd call
}

正如@rmaddy所示,您可以利用map(_:)可以接受投掷闭合的事实,并且会停止映射被丢弃的错误,将错误传播回呼叫者(您是您的)然后可以使用try?)。

对此有一个轻微的变化是定义自己的投掷cast(_:to:)功能以在转换闭合中调用:

struct TypeMismatchError : Error {
  var expected: Any.Type
  var actual: Any.Type
}
func cast<T, U>(_ x: T, to _: U.Type) throws -> U {
  guard let casted = x as? U else {
    throw TypeMismatchError(expected: U.self, actual: type(of: x))
  }
  return casted
}
func makeCodable(sourceArray: [Any]) -> [Codable]? {
  return try? sourceArray.map { try cast($0, to: Codable.self) }
}

尽管在这种情况下我们完全忽略了丢弃的错误,但我发现在其他情况下偶尔会有抛出施法功能有用(当然,您当然也可以通过使makeCodable成为投掷功能并使用try来传播错误)。

但是,所有人都说,请注意,您所产生的[Codable]?在当前形式中确实不太有用。您无法从中解码内容,因为您没有任何具体类型可以交接,也不能直接编码它,因为协议不符合自己(即Codable不符合Encodable),因此您可以't只需将Codable[Codable]移交给JSONEncoder)。

如果您实际上想对[Codable]进行一些编码,则需要将Encodable中的每个元素包裹在符合包装中,例如:

struct AnyEncodable : Encodable {
  var base: Encodable
  init(_ base: Encodable) {
    self.base = base
  }
  func encode(to encoder: Encoder) throws {
    try base.encode(to: encoder)
  }
}
func makeEncodable(sourceArray: [Any]) -> [AnyEncodable]? {
  return try? sourceArray.map {
    AnyEncodable(try cast($0, to: Encodable.self))
  }
}

现在[AnyEncodable]是您可以通过的东西,例如JSONEncoder

相关内容

  • 没有找到相关文章

最新更新