计算只读属性与Swift中的函数

在Swift简介会上,演示了一个只读的属性description

 class Vehicle { var numberOfWheels = 0 var description: String { return "\(numberOfWheels) wheels" } } let vehicle = Vehicle() println(vehicle.description) 

是否有任何意义,而不是使用一种方法来选择上述方法:

 class Vehicle { var numberOfWheels = 0 func description() -> String { return "\(numberOfWheels) wheels" } } let vehicle = Vehicle() println(vehicle.description()) 

在我看来,你会选择一个只读计算属性的最明显的原因是:

  • 语义 – 在这个例子中, description是类的一个属性,而不是它执行的动作。
  • 简洁/清晰 – 防止在获取价值时使用空圆括号。

显然,上面的例子过于简单,但是还有其他很好的理由选择一个吗? 例如,是否有一些功能或属性的特征可以指导您决定使用哪一个?


NB乍一看,这似乎是一个相当普遍的OOP问题,但我很想知道任何Swift特定的功能,将指导使用这种语言的最佳做法。

在我看来,这主要是一个风格问题:我强烈喜欢使用属性 :属性; 意思是您可以获取和/或设置的简单值。 在实际工作完成时,我使用函数 (或方法)。 也许有些东西需要从磁盘或从数据库中计算或读取:在这种情况下,我使用一个函数,即使只返回一个简单的值。 这样,我可以很容易地看到一个电话是便宜(属性)还是可能昂贵(功能)。

当Apple发布一些Swift编码规范时,我们可能会更清楚一些。

虽然一般来说计算属性与方法的问题是困难和主观的,但是在Swift的情况下,目前有一个重要的论点是偏好方法而不是属性。 你可以使用Swift中的方法作为纯粹的函数,对于属性来说是不正确的(从Swift 2.0 beta开始)。 这使得方法更加强大和有用,因为他们可以参与功能组合。

 func fflat<A, R>(f: (A) -> () -> (R)) -> (A) -> (R) { return { f($0)() } } func fnot<A>(f: (A) -> Bool) -> (A) -> (Bool) { return { !f($0) } } extension String { func isEmptyAsFunc() -> Bool { return isEmpty } } let strings = ["Hello", "", "world"] strings.filter(fnot(fflat(String.isEmptyAsFunc))) 

有一个区别:如果你使用一个属性,你可以最终覆盖它,并使其在子类中读/写。

由于运行时间是相同的,所以这个问题也适用于Objective-C。 我会说,你得到的财产

  • 在子类中添加setter的可能性,使属性readwrite
  • 使用KVO / didSet更改通知的功能
  • 更一般地说,您可以将属性传递给期望关键路径的方法,例如获取请求排序

至于特定于Swift的东西,我唯一的例子是你可以使用@lazy作为属性。

那么,你可以申请Kotlin的建议https://kotlinlang.org/docs/reference/coding-conventions.html#functions-vs-properties

在某些情况下,不带参数的函数可能与只读属性互换。 尽管语义是相似的,但是在某种程度上,它们之间存在着某种风格的约定。

当基础算法:

  • 不扔
  • 有一个O(1)
  • 计算复杂度是很便宜的(或者是在第一次运行时就能找到)
  • 通过调用返回相同的结果

在某些情况下,您更希望计算的属性超过正常的功能。 如:返回一个人的全名。 你已经知道名字和姓氏。 所以真正的fullName属性是一个属性而不是一个函数。 在这种情况下,它是计算属性(因为你不能设置全名,你可以使用名字和姓氏来提取它)

 class Person{ let firstName: String let lastName: String init(firstName: String, lastName: String){ self.firstName = firstName self.lastName = lastName } var fullName :String{ return firstName+" "+lastName } } let william = Person(firstName: "William", lastName: "Kinaan") william.fullName //William Kinaan 

从历史上看,描述是NSObject上的一个属性,很多人会认为它在Swift中仍然是一样的。 之后添加parens只会增加混淆。

编辑:愤怒downvoting后,我必须澄清的东西 – 如果它是通过点语法访问,它可以被视为一个属性。 引擎盖下的东西并不重要。 您不能使用点语法访问常规方法。

此外,称这个属性不需要额外的parens,就像Swift一样,这可能会导致混淆。