0

我正在尝试利用 Swift 中的协议和扩展,但遇到了一个我无法理解的编译错误。

如果我声明两个定义像这样的 Shape 的协议:

protocol Shape {
  var sides : Int { get }
  var fill : Fill { get }
}

protocol Fill {
  var color : UIColor { get }
}  

现在为了实现这一点,我定义了两个结构,一个用于方形,另一个用于实心填充。像这样:

struct SolidFill : Fill {
  var color : UIColor
}

struct Square : Shape {
  var sides : Int = 4
  var fill : SolidFill = SolidFill(color: UIColor.blackColor())
}

我收到一个编译错误“类型'Square'不符合协议'Shape'”。如果我强制填充类型为填充,就像var fill : Fill编译错误消失一样。为什么我不能让 Square 指定更具体的填充类型,那么协议允许什么?

我意识到对于这个特定的示例,我可以通过使用 Enum 进行填充或修改其他内容来改变事情以不使用此模式。我只是想知道为什么我不能让 fill 成为符合协议的类型。

4

2 回答 2

1

Because it wouldn't make sense.

Before you start writing code that conforms to protocols, you need to think about your protocols and realize that in a normal use case (and the way that your protocols should be designed), code will be written only with knowledge of the protocol and with zero knowledge of any specific class or struct which implements the protocol.

So, it does make sense for the Fill protocol to have other protocols that inherit from it, such as SolidFill and perhaps StripedFill.

Let's go ahead and add the StripedFill protocol to your example. Now let's look at your Square struct and see why it doesn't implement the Shape protocol, which in part requires having a Fill property.

struct Square : Shape {
  var sides : Int = 4
  var fill : SolidFill = SolidFill(color: UIColor.blackColor())
}

The only thing we can assign to Square's fill property are things which implement the SolidFill protocol. But the Shape protocol requires that our shape be able to assign to a property called fill anything which conforms to the Fill protocol. And in the case where we also have a protocol called StripedProtocol which inherits from the Fill protocol, that would include objects that implement that protocol (whether or not they also implement the SolidFill protocol).

But your Square class doesn't allow for this. Your Square class only allows for one specific child of Fill and its descendants, but not its sibling... and the exclusion of SolidFill's potential siblings is why you can't do what you're trying to do.

What you can do however is this:

struct Square: Shape {
    var sides: Int = 4
    var fill: Fill = SolidFill(color: UIColor.blackColor())
}

So in this case, we're still definitely assigning a SolidFill to our Square, but we're still allowing for the fill property to match what it defined in the protocol and allowing for SolidFill's siblings to be assigned to the fill property.

于 2015-11-10T13:35:53.240 回答
0

只有一个 getter 理论上可能没问题,但如果有一个 setter,它肯定不会满足协议,因为有人可能会尝试设置一个不同的对象来满足协议。

如果您认为它足够有价值,您可以提出一个雷达请求它仅获取 vars,但您可能更好地解决它。

你可以这样做:

struct Square : Shape {
  var sides : Int = 4
  var fill : Fill { solidFill }
  private var solidFill = SolidFill(color: UIColor.blackColor())
}
于 2015-11-10T13:35:08.020 回答