类和结构体/Classes and Structures
如何选择/Which one to use?
Remember, structs have value semantics. Use structs for things that do not have an identity. An array that contains [a, b, c] is really the same as another array that contains [a, b, c] and they are completely interchangeable. It doesn't matter whether you use the first array or the second, because they represent the exact same thing. That's why arrays are structs.
请记住,结构体有 值语义。对没有身份标识的事物使用结构体类型。一个包含 [a, b, c] 的数组和另一个包含 [a, b, c] 的数组是完全一样的。它们完全可以互换。使用第一个数组还是第二个数组都无所谓,因为它们代表着完全相同的事物。这就是为什么数组是结构体。
Classes have reference semantics. Use classes for things that do have an identity or a specific life cycle. You would model a person as a class because two person objects are two different things. Just because two people have the same name and birthdate, doesn't mean they are the same person. But the person's birthdate would be a struct because a date of 3 March 1950 is the same as any other date object for 3 March 1950. The date itself doesn't have an identity.
类有 引用语义。对有身份标识或有具体生命周期的事物使用类类型。你需要将人建模为一个类,因为不同的两个人是两个不同的事物。只是因为两个人拥有相同的名字和生日不意味着他们是同一个人。但是人的生日应该是一个结构体,因为 1950 年 3 月 3 日和任何其它的 1950 年 3 月 3 日日期对象是相同的。日期本身没有标识。
Sometimes, things should be structs but need to conform to AnyObject
or are historically modeled as classes already (NSDate
, NSSet
). Try to follow these guidelines as closely as possible.
有时,事物本应该是结构体,但需要遵循 AnyObject
,或由于历史原因已经被建模为类(NSDate
、 NSSet
)。不管怎样,都请尽可能遵循前面提到的原则。
示例/Example definition
Here's an example of a well-styled class definition:
下面是一个代码风格良好的类定义示例:
class Circle: Shape {
var x: Int, y: Int
var radius: Double
var diameter: Double {
get {
return radius * 2
}
set {
radius = newValue / 2
}
}
init(x: Int, y: Int, radius: Double) {
self.x = x
self.y = y
self.radius = radius
}
convenience init(x: Int, y: Int, diameter: Double) {
self.init(x: x, y: y, radius: diameter / 2)
}
override func area() -> Double {
return Double.pi * radius * radius
}
}
extension Circle: CustomStringConvertible {
var description: String {
return "center = \(centerString) area = \(area())"
}
private var centerString: String {
return "(\(x),\(y))"
}
}
The example above demonstrates the following style guidelines:
上面的例子遵循了以下代码规范:
Specify types for properties, variables, constants, argument declarations and other statements with a space after the colon but not before, e.g.
x: Int
, andCircle: Shape
.遵循冒号前无空格,冒号后有空格的规则,并应用在属性、变量、常量、参数声明和其它类型的语句中,例如:
x: Int
和Circle: Shape
。Define multiple variables and structures on a single line if they share a common purpose / context.
如果多个变量和结构体遵循同一目的 / 上下文,则可以在同一行中定义。
Indent getter and setter definitions and property observers.
缩进 getter、setter 的定义和属性观察器。
Don't add modifiers such as
internal
when they're already the default. Similarly, don't repeat the access modifier when overriding a method.不要将默认的修饰符重复添加到代码中,例如
internal
关键字。类似的,当重写一个方法时,不要再重复添加与访问权限相关的修饰符。Organize extra functionality (e.g. printing) in extensions.
在扩展中组织额外功能(例如打印相关的代码)。
Hide non-shared, implementation details such as
centerString
inside the extension usingprivate
access control.利用隐藏非共享的实现细节,例如在扩展中实现
centerString
方法并设置private
级别的访问控制权限。
Self 的使用/Use of Self
For conciseness, avoid using self
since Swift does not require it to access an object's properties or invoke its methods.
为了简洁,请避免使用 self
关键词,Swift 不需要用它来访问一个对象属性或调用它的方法。
Use self only when required by the compiler (in @escaping
closures, or in initializers to disambiguate properties from arguments). In other words, if it compiles without self
then omit it.
仅在编译器需要时(在 @escaping
闭包或初始化函数中消除参数与属性的歧义)才使用 self。换句话说,如果不需要 self
就能编译通过,可以忽略它。
计算属性/Computed Properties
For conciseness, if a computed property is read-only, omit the get clause. The get clause is required only when a set clause is provided.
为了简洁,如果一个计算属性是只读的,可以忽略 get 子句。仅在 set 子句存在的情况下才需要 get 子句。
推荐(Preferred):
var diameter: Double {
return radius * 2
}
不推荐(Not Preferred):
var diameter: Double {
get {
return radius * 2
}
}
Final 关键字/Final
Marking classes or members as final
in tutorials can distract from the main topic and is not required. Nevertheless, use of final
can sometimes clarify your intent and is worth the cost. In the below example, Box
has a particular purpose and customization in a derived class is not intended. Marking it final
makes that clear.
在教程中将类或成员标记为 final
会偏离主题,且不是必需的。不过有时 final
的使用可以明确你的意图,也值得你这样做。在下面的例子中,Box
有特定的用途,且不打算在派生类中进行自定义。标记为 final
可以使它更清晰。
// Turn any generic type into a reference type using this Box class.
final class Box<T> {
let value: T
init(_ value: T) {
self.value = value
}
}