本文翻译自苹果官方文档:Swift API Design Guidelines,如有错漏,欢迎指出。
extension List {
public mutating func remove(at position: Index) -> Element
}
employees.remove(at: x)
如果我们删掉方法签名中的at
,那就给人一种该方法是搜索并删除集合中等于x
的元素的感觉,而不是用x
来指示元素在集合中的位置,并把该位置的元素删除。
不推荐:
employees.remove(x) // unclear: are we removing x?
public mutating func removeElement(member: Element) -> Element?
allViews.removeElement(cancelButton)
上述情况下,Element
在调用处没有提供任何要点信息,如下 API 会更好。
推荐:
public mutating func remove(member: Element) -> Element?
allViews.remove(cancelButton) // clearer
个别情况下,重复类型信息对于消除歧义是必要的,但一般来说,用一个表明参数角色(role)而不是类型的词,会更好一些。详情请参看下一条。 基于变量、参数、关联类型的角色来对它们进行命名,而不是基于它们的类型。 不推荐:
var string = "Hello"
protocol ViewController {
associatedtype ViewType : View
}
class ProductionLine {
func restock(from widgetFactory: WidgetFactory)
}
像这样重申一遍类型名并不能最大程度提升明确性和表现力。相反,我们应该尽量选用那些表明实体角色的名字。 推荐:
var greeting = "Hello"
protocol ViewController {
associatedtype ContentView : View
}
class ProductionLine {
func restock(from supplier: WidgetFactory)
}
如果某个关联类型和它的协议联系非常紧密,以至于它的协议名就是它的角色名,那就给关联类型的名字加上Type
避免冲突:
protocol Sequence {
associatedtype IteratorType : Iterator
}
NSObject、Any、 AnyObject
或者像Int、String
这样的基本类型的时候,调用处的类型信息和上下文环境可能不能完全表明函数的意图。如下这个例子,它的声明可能是明确的,但在调用的地方就显得意图不明了。
不推荐:func add(observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // vague
为了恢复明确性,在每个弱类型参数前加一个名词用来描述它的角色。 推荐:
func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear
x.insert(y, at: z) “x, insert y at z”
x.subViews(havingColor: y) “x's subviews having color y”
x.capitalizingNouns() “x, capitalizing nouns”
不推荐:
x.insert(y, position: z)
x.subViews(color: y)
x.nounCapitalize()
为了流畅性,可以把调用时非重点的参数放到第一或者第二个参数之后。
AudioUnit.instantiate(
with: description,
options: [.inProcess], completionHandler: stopProgressBar)
make
开头,譬如:x.makeIterator()
。x.makeWidget(cogCount: 47)
。
举个例子,如下这些调用的短语都不包含 first argument。
推荐:let foreground = Color(red: 32, green: 64, blue: 128)
let newPart = factory.makeWidget(gears: 42, spindles: 14)
而下面这段代码的 API 作者企图用 first argument 创建符合英语语法的顺畅 API: 不推荐:
let foreground = Color(havingRGBValuesRed: 32, green: 64, andBlue: 128)
let newPart = factory.makeWidget(havingGearCount: 42, andSpindleCount: 14)
事实上,本指南包含了参数标签(argument labels,译者注:应该和外部参数名一个意思吧)这样的的主题,意味着第一个参数都应该包含一个标签,除非该方法完全只是用来做类型转换的。 推荐:
let rgbForeground = RGBColor(cmykForeground)
x.distance(to: y)
, i.successor()
。print(x)
, x.sort()
, x.append(y)
。/// Reverses `self` in-place.
mutating func reverse()
/// Returns a reversed copy of `self`.
func reversed() -> Self
...
x.reverse()
let y = x.reversed()
- 当动词后面跟了个名词的时候,用过去分词就不符合语法规范了,这时候可以用动词的现在分词对不可变版本命名,也就是加上 “ing”:
/// Strips all the newlines from \`self\`
mutating func stripNewlines()
/// Returns a copy of \`self\` with all the newlines stripped.
func strippingNewlines() -> String
...
s.stripNewlines()
let oneLine = t.strippingNewlines()
x.isEmpty
, line1.intersects(line2)
。Collection
)。Equatable
, ProgressReporting
)。