Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift:协议扩展中的静态属性可以被覆盖,但为什么?_Ios_Swift_Swift2 - Fatal编程技术网

Ios Swift:协议扩展中的静态属性可以被覆盖,但为什么?

Ios Swift:协议扩展中的静态属性可以被覆盖,但为什么?,ios,swift,swift2,Ios,Swift,Swift2,我观看并阅读了相关文档,但我仍然认为以下示例代码中存在冲突(请在操场上尝试) 协议X{ //重要的部分是“静态”关键字 静态变量x:String{get} } 扩展X{ //这里又是“静态” 静态变量x:String{ 得到{ 返回“xxx” } } } //现在我要在一个类中使用协议,但是 //在类中,“静态”类似于“最终类”, //也就是说,不能被覆盖,对吗? //但我更希望能覆盖这个属性, //所以我将尝试使用“class”关键字。 //它会破坏程序吗?(剧透:没有!) Y类:X类{ //

我观看并阅读了相关文档,但我仍然认为以下示例代码中存在冲突(请在操场上尝试)

协议X{
//重要的部分是“静态”关键字
静态变量x:String{get}
}
扩展X{
//这里又是“静态”
静态变量x:String{
得到{
返回“xxx”
}
}
}
//现在我要在一个类中使用协议,但是
//在类中,“静态”类似于“最终类”,
//也就是说,不能被覆盖,对吗?
//但我更希望能覆盖这个属性,
//所以我将尝试使用“class”关键字。
//它会破坏程序吗?(剧透:没有!)
Y类:X类{
//这里我们可以使用“class”关键字(但为什么?)。
类var x:String{
得到{
返回“yyy”
}
}
}
Z类:Y类{
重写类var x:String{
得到{
返回“zzz”
}
}
}
课堂测试{
func test()->字符串{
返回T.x
}
}
//最后,该属性被成功覆盖(但为什么?)。
打印(Test().Test())/“zzz\n”
这实际上是否意味着当协议在类中使用时,协议中的
静态
关键字(以及可能的默认实现)可以合法地替换为
关键字?你知道有任何证明这一点的参考资料吗?

从中我们知道以下内容

函数声明

特殊类型的方法

与类型而非类型实例关联的方法必须使用枚举和结构的
静态
声明修饰符或类的
声明修饰符进行标记

也就是说,
static
关键字(主要)用于枚举和结构,
class
关键字用于类

还有这样一个注释:

类型变量属性

注 在类声明中,关键字
static
与使用
class
final
声明修饰符标记声明具有相同的效果

也就是说,
static
关键字实际上可以在类声明中使用,并且将意味着
最终类

那么协议呢? 协议方法声明

要在协议声明中声明类或静态方法需求,请使用
static
声明修饰符标记方法声明。实现此方法的类使用
class
修饰符声明该方法。实现它的结构必须使用
static
声明修饰符声明方法。如果在扩展中实现该方法,则在扩展类时使用
修饰符,在扩展结构时使用
静态
修饰符

这里的文档说明,在类或类扩展中实现协议时,我们应该将协议声明中的
static
关键字替换为
class
关键字(这是对原始问题的准确答案)

奖金 有两种情况下,协议采用仅限于类。第一个(也是最不明确的)是当协议包含
可选成员时:

议定书声明

默认情况下,符合协议的类型必须实现协议中声明的所有属性、方法和下标。也就是说,您可以使用
optional
声明修饰符标记这些协议成员声明,以指定它们通过一致类型的实现是可选的。
可选
修饰符只能应用于标有
objc
属性的协议。因此,只有类类型可以采用并符合包含可选成员要求的协议

第二段(明确;下一段):

要将协议的采用仅限于类类型,请将
class
关键字作为继承协议列表中冒号后的第一项,用
class
要求标记协议


但是考虑到
静态
关键字的适用性,它们都没有改变规则。

从文档中可以明显看出这一点。更有趣的问题是,在类中使用协议时,用
关键字替换原来的
静态
是否合法?对不起,这同样很简单(因为文档中确实提到了它们),但没有一个词说明如何
静态
(这可能意味着
最终类
)在协议中,可以在实现此类协议的类中用
(这可能意味着“忘记
最终版
”)替换。这合法吗?文档中有描述吗?我认为答案是“是的,它是合法的(我们已经检查过了),而不是,它没有在文档中描述”:(它可能意味着最终的,但正如我们所看到的,在这里它不是Tyes。但是你同意文档在这一点上不够明确吗?(目前这种知识只能通过实验提取)我把文档理解为只有
final类
防止子类重写,
static
本身不这样做。它强制只在类内实现
class
关键字,这并不意味着它是
final
protocol X {

    // The important part is "static" keyword
    static var x: String { get }
}

extension X {
    // Here "static" again
    static var x: String {
        get {
            return "xxx"
        }
    }
}

// Now I'm going to use the protocol in a class, BUT
// in classes "static" is like "final class",
// i.e. CAN'T BE OVERRIDDEN, right?

// But I'd prefer to have the ability to override that property,
// so I'll try to use "class" keyword.
// Will it break the program? (spoiler: no!)

class Y: X {
    // Here we are allowed to use "class" keyword (but why?).
    class var x: String {
        get {
            return "yyy"
        }
    }
}

class Z: Y {
    override class var x: String {
        get {
            return "zzz"
        }
    }
}

class Test<T: X> {
    func test() -> String {
        return T.x
    }
}

// And finally the property is successfully overridden (but why?).
print(Test<Z>().test()) // "zzz\n"