本文介绍了Swift:在[< SomeType< T&gt ;?]上扩展以产生[< T&gt ;?]可能吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Swift中,我有一个具有以下基本前提的自定义结构:

包装器结构,可以包含符合BinaryInteger的任何类型,例如Int,UInt8,Int16等.

A wrapper struct that can contain any type that conforms to BinaryInteger such as Int, UInt8, Int16, etc.

protocol SomeTypeProtocol {
    associatedtype NumberType

    var value: NumberType { get set }
}

struct SomeType<T: BinaryInteger>: SomeTypeProtocol {
    typealias NumberType = T

    var value: NumberType
}

以及Collection的扩展名:

And an extension on Collection:

extension Collection where Element: SomeTypeProtocol {
    var values: [Element.NumberType] {
        return self.map { $0.value }
    }
}

例如,这很好用:

let arr = [SomeType(value: 123), SomeType(value: 456)]

// this produces [123, 456] of type [Int] since literals are Int by default
arr.values

我想做的是完全相同的事情,但对于SomeType<T>?

What I would like to do is the exact same thing, but for SomeType<T>?

let arr: [SomeType<Int>?] = [SomeType(value: 123), SomeType(value: 456)]

// this doesn't work, obviously
arr.values

// but what I want is this:
arr.values // to produce [Optional(123), Optional(456)]

我已经尝试了许多尝试来解决这个问题,并进行了大量研究,但我希望Swift的资深人士中的任何一位智者都可以对此有所了解.

I've tried numerous attempts to solve this and a fair amount of research, but I'm hoping any of the sage Swift veterans might shed some light on this.

这是我预期的样子,但这不起作用:

This is what I envision it might look like, but this doesn't work:

extension Collection where Element == Optional<SomeType<T>> {
    var values: [T?] {
        return self.map { $0?.value }
    }
}

这是不使用泛型即可达成目标的笨拙方法,并且有效:

extension Collection where Element == Optional<SomeType<Int>> {
    var values: [Int?] {
        return self.map { $0?.value }
    }
}

let arr: [SomeType<Int>?] = [SomeType(value: 123), SomeType(value: 456)]
arr.values // [Optional(123), Optional(456)]

但是它需要为符合BinaryInteger的每个已知类型手动编写扩展名,并且在不手动更新代码的情况下不会自动包含采用BinaryInteger的将来类型.

But it requires manually writing extensions for every known type conforming to BinaryInteger, and will not automatically include possible future types adopting BinaryInteger without manually updating the code.

// "..." would contain the var values code from above, copy-and-pasted
extension Collection where Element == Optional<SomeType<Int>> { ... }
extension Collection where Element == Optional<SomeType<Int8>> { ... }
extension Collection where Element == Optional<SomeType<UInt8>> { ... }
extension Collection where Element == Optional<SomeType<Int16>> { ... }
extension Collection where Element == Optional<SomeType<UInt16>> { ... }
extension Collection where Element == Optional<SomeType<Int32>> { ... }
extension Collection where Element == Optional<SomeType<UInt32>> { ... }
extension Collection where Element == Optional<SomeType<Int64>> { ... }
extension Collection where Element == Optional<SomeType<UInt64>> { ... }

编辑2018年6月23日:

解决方案#1-完全通用,但必须是功能而非计算属性

Ole的回复上展开:

优点:如果values()成为func而不是计算属性,则这是一个很好的解决方案.

Pros: If values() becomes a func and not a computed property, this is an elegant solution.

缺点:没有一种将这种方法实现为计算属性的方法,Swift的快速帮助弹出窗口在检查代码中的values()时显示[T]和[T?].即:它只是说func values<T>() -> [T] where T : BinaryInteger,它不是非常有用的信息或Swifty.但是,当然它仍然是强类型的.

Cons: No known way to implement this approach as computed properties, and Swift's Quick Help popup shows [T] and [T?] when inspecting values() in your code. ie: it just says func values<T>() -> [T] where T : BinaryInteger which isn't very informative or Swifty. However it still remains strongly typed of course.

extension Collection {
    func values<T>() -> [T] where Element == SomeType<T> {
        return map { $0.value }
    }

    func values<T>() -> [T?] where Element == SomeType<T>? {
        return map { $0?.value }
    }
}

解决方案2-可选协议解决方法

马丁的回信中扩展:

优点:允许使用计算属性(由于不需要func parens,因此最终用户可以使用更干净的属性),并在Xcode的快速帮助"弹出窗口中显示推断的类型.

Pros: Allows use of computed properties (cleaner for the end-user to access since it doesn't require func parens) and shows inferred type in Xcode's Quick Help popup.

缺点:从内部代码的角度来看,这不是很优雅,因为它需要一种解决方法.但不一定是缺点.

Cons: Not as elegant from an internal code standpoint, as it requires a workaround. But not necessarily a drawback.

// Define OptionalType

protocol OptionalType {
    associatedtype Wrapped
    var asOptional: Wrapped? { get }
}

extension Optional: OptionalType {
    var asOptional: Wrapped? {
        return self
    }
}

// Extend Collection

extension Collection where Element: SomeTypeProtocol {
    var values: [Element.NumberType] {
        return self.map { $0.value }
    }
}

extension Collection where Element: OptionalType, Element.Wrapped: SomeTypeProtocol {
    var values: [Element.Wrapped.NumberType?] {
        return self.map { $0.asOptional?.value }
    }
}

推荐答案

我不知道现在是否有一个更简单的解决方案,但是您可以使用与我该如何写一个函数和,这个想法可以追溯到此Apple论坛主题.

I don't know if there is a simpler solution now, but you can use the same "trick" as in How can I write a function that will unwrap a generic property in swift assuming it is an optional type? and Creating an extension to filter nils from an Array in Swift, the idea goes back to this Apple Forum Thread.

首先定义所有可选选项都遵循的协议:

First define a protocol to which all optionals conform:

protocol OptionalType {
    associatedtype Wrapped
    var asOptional: Wrapped? { get }
}

extension Optional : OptionalType {
    var asOptional: Wrapped? {
        return self
    }
}

现在所需的扩展名可以定义为

Now the desired extension can be defined as

extension Collection where Element: OptionalType, Element.Wrapped: SomeTypeProtocol {
    var values: [Element.Wrapped.NumberType?] {
        return self.map( { $0.asOptional?.value })
    }
}

并且可以按预期工作:

let arr = [SomeType(value: 123), nil, SomeType(value: 456)]
let v = arr.values

print(v) // [Optional(123), Optional(456)]
print(type(of: v)) // Array<Optional<Int>>

这篇关于Swift:在[&lt; SomeType&lt; T&gt ;?]上扩展以产生[&lt; T&gt ;?]可能吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 15:44