如何确定泛型在Swift中是否可选? [英] How to determine if a generic is an optional in Swift?

查看:121
本文介绍了如何确定泛型在Swift中是否可选?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用一个函数来扩展一个Array,该函数将返回一个Array中所有非零项的计数。理想情况下,这可以与任何可选或非可选类型的数组一起使用。我尝试了各种无法编译的东西,Xcode或两者都崩溃。我会假设它看起来像这样:

 扩展数组{
func realCount() - > Int {
var cnt = 0
for self {
if value!= nil {
cnt ++
}
}

return cnt


code
$ b

这里Swift抱怨 T 不能转换为 UInt8 。或者有时候 MirrorDisposition 或其他随机类。



所以假设它是可能的,这有什么用? b
$ b

编辑:从Xcode 6 beta 5开始编译,但是没有给出预期的结果。 if value!= nil 每次评估结果为真。 不要将任意值与 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

这种方法更加灵活。 可选只是您希望以这种方式绘制flatMap的许多类型之一(例如,您可以使用相同的技术来处理结果)。






编辑:您可以通过为您认为真实的事物创建一个协议来进一步实现。这样你就不必把它限制在Optionals中。例如:

  protocol Realizable {
func isReal() - > Bool
}

扩展可选:可实现{
func isReal() - > Bool {return self.getLogicValue()}
}

func countReal< S:Collection>(x:S) - > S.IndexType.DistanceType {
return countElements(x)
}

func countReal< S:Collection其中S.GeneratorType.Element:Realizable>(x:S) - > ; Int {
return countElements(filter(x,{$ 0.isReal()}))
}

这就是说,如果我传递一系列可实现的东西,然后根据它们的规则进行筛选。否则,只要数它们。虽然我可能不会真的使用这个函数(这看起来很特殊),但这个概念很有用。稍后的调用者可以添加新的可实现类型,而无需修改任何代码(甚至不知道它们是如何实现的)。这显示了如何为不执行协议的事情设置默认行为。

顺便说一句,我在这里使用集合只是因为它们更易于计数(而且我对返回类型有点sl;,注意一个是DistanceType,另一个是Int)。在泛型基于集合的函数上获取类型仍然很棘手(并且经常会使编译器崩溃)。我怀疑这将在下一次测试中有所改善。


I want to extend an Array with a function that would return a count of all non-nil items in an Array. Ideally this would work with an array of any optional or non-optional types. I tried a variety of things that failed to compile, crashed Xcode or both. I would have assumed it would look something like this:

extension Array {
    func realCount() -> Int {
        var cnt = 0
        for value in self {
            if value != nil {
                cnt++
            }
        }

        return cnt
    }
}

Here Swift complains that T is not convertible to UInt8. Or sometimes MirrorDisposition or other random classes.

So assuming it's possible, what's the trick?

Edit: as of Xcode 6 beta 5 this now compiles but does not give the expected results. if value != nil evaluates true every time.

解决方案

You can't compare an arbitrary value to nil (EDIT: but see Sulthan's comment below; it may be that we should be able to compare arbitrary values to nil; the rest of this paragraph may be true today, but only due to a compiler bug). While Optional has some bits of syntactic sugar applied to it, it's really just a enum, and nil is just Optional.None. You want one behavior for one type (Optional) and another behavior for all other types. Swift has that via generics, just not in extensions. You have to turn it around into a function:

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

This approach is much more flexible. Optional is just one of many types you would want to flatMap this way (for example, you could use this same technique to handle Result).


EDIT: You can take this further by creating a protocol for things you consider "real." That way you don't have to confine this to Optionals. For example:

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()}))
}

This says, if I pass a collection of "realizable" things, then filter them against their rule. Otherwise, just count them. While I probably wouldn't really use this function (it seems very special-case), the concept is useful. Later callers can add new "realizable" types without modifying any of your code (or even knowing how they're implemented). And this shows how to have a default behavior for things that don't implement your protocol.

BTW, I'm using Collections here just because they're easier to count (and I'm being a bit sloppy about the return types; notice one is the DistanceType and the other is an Int). Getting the types right on generic Collection-based functions is still kind of tricky (and often crashes the compiler). I suspect this will all improve in the next betas.

这篇关于如何确定泛型在Swift中是否可选?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆