在Swift中键入强制问题 [英] Type coercion issue in Swift

查看:121
本文介绍了在Swift中键入强制问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有两个协议, X Y 其中 Y implements X ,为什么我不能将 Y 数组赋给类型 [X]



更奇怪的是,我可以将它一个一个转换成X数组,罚款。

 协议X {} 

协议Y:X {}

//创建Y
扩展的测试数组String:Y {}
let a:[Y] = [Hello]

//数组X - 这工作绝对精细
let b:[X] = [a [0] as X]

//为什么这个转换不工作?
let c:[X] = a as [X]

所有的X都可以做,这个赋值应该很好(是的,我输了一些类型的信息,但至少应该编译!)



任何想法?

编辑:当前答案指出,这是一个危险的事情,如果你正在使用可变数组 - 我没有得到,但现在:)但是,如果我的数组都是不可变的,为什么不会Swift让这种情况发生?即使 c 是一个可变数组(即 var c = a as [X] ), c>

解决方案

它可能会产生一些问题。例如:

  var squares:Array< Square> = Array< Square>()
(正方形为[Shape])。append(Circle())


$ b b

现在我们在正方形数组中有一个圆。我们不想要,所以编译器不让我们。在其他语言如Scala中,您可以指定泛型为协变 contravariant code>。



如果Swift允许您使用协变泛型 Array< Square> 将是 Array< Shape> 的子类型。



如果使用 contravariance a Array< Square> 将是 Array< Shape> 的超类型

但是当使用不变泛型时,两者都不是子类型。



在你的情况下可能是这样:

  let c = a.map {$ 0 as X} 

现在 c 的类型为 [X ]



有关类型差异的详细信息及其可能有问题的访问,可以访问此维基页



编辑:进一步来回,似乎真正的问题是,协议允许默认实现,因此可能会导致问题。当使用类时,你的代码将无缺陷地编译。下面是一些可能导致协议问题的代码:

 协议Shape {
func surfaceArea Double
}

扩展Shape {
func surfaceArea() - > Double {
return 0.0
}
}

protocol Circle:Shape {
func getRadius() - > Double
}

扩展圈{
func surfaceArea() - > Double {
return getRadius()* getRadius()* 3.14
}
}

现在,当我们在这两个协议之间上传时, surfaceArea()方法返回不同的值,Swift不允许它。



尝试同样的事情与类,而不是协议和Swift将不会有任何问题编译您当前的代码。对我来说,这是Swift团队的一个奇怪的决定,但我仍然认为最好的方法是使用

  let c = a.map {$ 0 as X} 


If I have two protocols, X and Y where Y implements X, why can't I assign an array of Y to a variable with the type [X]?

Even more curiously, I can convert it one by one into an array of X, and that compiles fine.

protocol X { }

protocol Y: X { }

// Make a test array of Y
extension String: Y { }
let a: [Y] = [ "Hello" ]

// Make it into an array of X - this works absolutely fine
let b: [X] = [ a[0] as X ]

// Why won't this cast work?
let c: [X] = a as [X]

I thought that given Y does everything X can do, this assignment should be fine (yea, I lose some type information, but it should at least compile!)

Any ideas?

EDIT: The current answer points out that it's a dangerous thing to do if you are using mutable arrays - which I didn't get but do now :) However, if my arrays are all immutable why won't Swift let this happen? Even if c is a mutable array (i.e. var c = a as [X]) why won't Swift copy it, leaving a intact?

解决方案

This doesn't work because it could create a few problems. For example:

var squares: Array<Square> = Array<Square>()
(squares as [Shape]).append(Circle())

Now we have a circle in our Array of Squares. We don't want that, so the compiler doesn't let us. In other languages like Scala you can specify generics to be covariant, contravariant or invariant.

If Swift would let you use covariant generics an Array<Square> would be a subtype of Array<Shape>.

If using contravariance an Array<Square> would be a supertype(!) of Array<Shape>.

But when using invariant generics, neither is the subtype of neither.

The easiest way to do it in your case would probably be this:

let c = a.map{$0 as X}

Now c is of type [X].

For more information on type variance and why it can be problematic visit, you can visit this wiki page.

EDIT: After further back and forth, it seems the real problem is, that Protocols allow default implementations and can therefore cause problems. Your code will compile flawlessly when using classes. Here's some code that could potentially lead to problems with protocols:

protocol Shape {
    func surfaceArea() -> Double
}

extension Shape {
    func surfaceArea() -> Double {
        return 0.0
    }
}

protocol Circle : Shape {
    func getRadius() -> Double
}

extension Circle {
    func surfaceArea() -> Double {
        return getRadius() * getRadius() * 3.14
    }
}

Now, when we upcast between these two protocols, the surfaceArea() method returns different values, and Swift doesn't allow it.

Try the same thing with classes, instead of protocols and Swift won't have any problems compiling your current code. This is, to me, kind of a weird decision by the Swift team, but I still think the best way to mitigate is to just use

let c = a.map{$0 as X}

这篇关于在Swift中键入强制问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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