我想用一个函数扩展一个数组,该函数将返回数组中所有非零项的计数。理想情况下,这将适用于任何可选或非可选类型的数组。我尝试了各种编译失败、Xcode 崩溃或两者兼而有之的尝试。我本以为它看起来像这样:
extension Array {
func realCount() -> Int {
var cnt = 0
for value in self {
if value != nil {
cnt++
}
}
return cnt
}
}
这里 Swift 提示 T
不能转换为 UInt8
。或者有时 MirrorDisposition
或其他随机类。
假设这是可能的,有什么窍门?
编辑:从 Xcode 6 beta 5 开始,它现在可以编译但没有给出预期的结果。 if value != nil
每次都计算为 true。
最佳答案
您不能将任意值与 nil
进行比较(编辑:但请参阅下面 Sulthan 的评论;可能我们应该能够将任意值与 nil
;本段的其余部分在今天可能是正确的,但只是由于编译器错误)。虽然 Optional
应用了一些语法糖,但它实际上只是一个枚举,而 nil
只是 Optional.None
。您希望一种类型有一种行为(可选
),而另一种行为适用于所有其他类型。 Swift 通过泛型实现这一点,而不是在扩展中。你必须把它变成一个函数:
func realCount<T>(x: [T?]) -> Int {
return countElements(filter(x, { $0.getLogicValue() } ) )
}
func realCount<T>(x: [T]) -> Int {
return countElements(x)
}
let l = [1,2,3]
let lop:[Int?] = [1, nil, 2]
let countL = realCount(l) // 3
let countLop = realCount(lop) // 2
这种方法更加灵活。 Optional
只是您希望以这种方式进行 flatMap 的众多类型之一(例如,您可以使用相同的技术来处理 Result )。
编辑:您可以通过为您认为“真实”的事物创建协议(protocol)来更进一步。这样你就不必将它限制在 Optionals 中。例如:
protocol Realizable {
func isReal() -> Bool
}
extension Optional: Realizable {
func isReal() -> Bool { return self.getLogicValue() }
}
func countReal<S:Collection>(x: S) -> S.IndexType.DistanceType {
return countElements(x)
}
func countReal<S:Collection where S.GeneratorType.Element:Realizable>(x: S) -> Int {
return countElements(filter(x, {$0.isReal()}))
}
这就是说,如果我传递一组“可实现”的东西,然后根据它们的规则过滤它们。否则,只需计算它们。虽然我可能不会真正使用这个函数(它看起来很特殊),但这个概念很有用。以后的调用者可以添加新的“可实现”类型,而无需修改您的任何代码(甚至不知道它们是如何实现的)。这展示了如何为未实现您的协议(protocol)的事物设置默认行为。
顺便说一句,我在这里使用 Collections 只是因为它们更容易计数(而且我对返回类型有点马虎;注意一个是 DistanceType,另一个是 Int)。在基于通用集合的函数上获得正确的类型仍然有点棘手(并且经常使编译器崩溃)。我怀疑这一切都会在下一个测试版中得到改善。
关于generics - 如何确定泛型在 Swift 中是否是可选的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25064644/