Swift 中表示 “类型范围作用域” 这一概念有两个不同的关键字,它们分别是 static
和 class
。这两个关键字确实都表达了这个意思,但是在其他一些语言,包括 Objective-C 中,我们并不会特别地区分类变量/类方法和静态变量/静态函数。但是在 Swift 中,这两个关键字却是不能用混的。
在非 class
的类型上下文中,我们统一使用 static
来描述类型作用域。这包括在 enum
和 struct
中表述类型方法和类型属性时。在这两个值类型中,我们可以在类型范围内声明并使用存储属性,计算属性和方法。static
适用的场景有这些:
struct Point {
let x: Double
let y: Double
// 存储属性
static let zero = Point(x: 0, y: 0)
// 计算属性
static var ones: [Point] {
return [Point(x: 1, y: 1),
Point(x: -1, y: 1),
Point(x: 1, y: -1),
Point(x: -1, y: -1)]
}
// 类型方法
static func add(p1: Point, p2: Point) -> Point {
return Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
}
enum
的情况与这个十分类似,就不再列举了。
class
关键字相比起来就明白许多,是专门用在 class 类型的上下文中的,可以用来修饰类方法以及类的计算属性。要特别注意 class
中现在是不能出现存储属性的,我们如果写类似这样的代码的话:
class MyClass {
class var bar: Bar?
}
编译时会得到一个错误:
class variables not yet supported
这主要是因为在 Objective-C 中就没有类变量这个概念,为了运行时的统一和兼容,暂时不太方便添加这个特性。Apple 表示今后将会考虑在某个升级版本中实装 class 类型的类存储变量,现在的话,我们只能在 class
中用 class
关键字声明方法和计算属性。
有一个比较特殊的是 protocol
。在 Swift 中 class
,struct
和 enum
都是可以实现某个 protocol
的。那么如果我们想在 protocol
里定义一个类型域上的方法或者计算属性的话,应该用哪个关键字呢?答案是使用 static
进行定义,但是在用具体的类型来实现时还是按照上面的规则:在 struct
或 enum
中仍然使用 static
,而在 class
里使用 class
关键字 -- 虽然在 protocol
中定义时使用的是 static
:
protocol MyProtocol {
static func foo() -> String
}
struct MyStruct: MyProtocol {
static func foo() -> String {
return "MyStruct"
}
}
enum MyEnum: MyProtocol {
static func foo() -> String {
return "MyEnum"
}
}
class MyClass: MyProtocol {
class func foo() -> String {
return "MyClass"
}
}
在 Swift 1.2 之前 protocol
中使用的是 class
作为关键字,但这确实是不合逻辑的。Swift 1.2 对此进行了改进,现在只需要记住除了确实是具体的 class
以外,其他情况都使用 static
就行了。