Swift:扩展可选数组

10

我想扩展 Optional,其中Wrapped是一个数组(其元素可以是任何类型)。换句话说,我想向[Any]?添加一个函数。我只是不确定如何声明它。我已经尝试了:

1.

extension Optional where Wrapped: Array

导致结果为:

error: reference to generic type 'Array' requires arguments in <...>

2.

extension Optional where Wrapped: Array<Any>

导致:

type 'Wrapped' constrained to non-protocol type 'Array<Any>'

还有其他类似的声明。需要帮助。


2
这个扩展具体是什么?换句话说,你希望添加到 [Any] 中的功能是什么? - matt
1
我想添加一个方便的函数,它可以1)在数组非空时附加元素,并且2)如果数组为空,则只使用该元素初始化数组。 - Connor Neville
2
@ConnorNeville 你的意思是 array = (array ?? []) + [element] 吗?在我看来,这并不值得写成一个扩展(考虑到为了让它正常工作而必须经历的解决方法)。 - Hamish
哦,这种方法比我一直写的更简洁。我会采用这种方法,谢谢。 - Connor Neville
@ConnorNeville 没问题 :) 虽然我确实觉得有必要对可选数组的使用进行质疑,但它不能只是一个非可选的空数组吗? - Hamish
4个回答

15

我可能有点晚了,但或许我可以帮忙。

在 Swift 4 中,你可以这样做:

extension Optional where Wrapped: Collection {

如果你需要访问数组的 Element 类型,你可以这样做:

Wrapped.Iterator.Element


1
感谢您指向了Collection协议,这正是我需要的。 - heyfrank

2
有些晚了,但这仍然可能对未来的读者有所帮助。使用Wrapped RangeReplaceableCollection来支持字符串:
extension Optional where Wrapped: RangeReplaceableCollection {
    mutating func append(_ element: Wrapped.Element) {
        self = (self ?? .init()) + CollectionOfOne(element)
    }
    mutating func append<S: Sequence>(contentsOf sequence: S) where S.Element == Wrapped.Element {
        self = (self ?? .init()) + sequence
    }
}

var optionalString: String?
optionalString.append("a")
optionalString  //  "a"
optionalString.append(contentsOf: "bc")
optionalString  //  "abc"
optionalString.append(contentsOf: ["d", "e"])
optionalString  //  "abcde"
var optionalArray: [Int]?
optionalArray.append(1)
optionalArray  //  [1]
optionalArray.append(contentsOf: [2,3])
optionalArray  //  [2,3]

2

是的,这里的问题在于这一行:

extension Optional where Wrapped: Array<Any>

“Array” 应该是一种协议,以更通用的方式表达:
extension Type where Element: Protocol 

我得到的解决方案虽然不太美观,但是可行,请考虑以下内容:
protocol ArrayOfAny {}
struct ArrayAny<Element: Any>: ArrayOfAny {
    let array: [Element]
    init(_ array: [Element]) {
        self.array = array
    }
}    

因为这个原因:
extension Array: ArrayOfAny where Element: Any {}

不支持...

那么你可以这样做:

extension Optional where Wrapped: ArrayOfAny

希望能对您有所帮助 :)

0
一个更好的解决方案是在 `Optional` 上使用泛型函数,像这样(只有在它确实是一个 `Array` 时才会向 `Optional` 添加函数):
extension Optional {
    mutating func appendAndSetIfNil<E>(_ element: Wrapped.Element) where Wrapped == [E] {
        self = (self ?? []) + [element]
    }

    mutating func appendAndSetIfNil<S>(contentsOf newElements: S) where S: Sequence, Wrapped == [S.Element] {
        self = (self ?? []) + newElements
    }
}

这只是一个示例,其中append函数基本上已根据其Wrapped类型为Array有条件地添加到Optional中。在这种情况下,值在附加之前从nil更改为[]

但你可以在这里做任何事情!

请注意,这种方法并非在所有情况下都适用,但在此情况下有效!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接