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

Stu*_*art 95 methods properties semantics swift

在Swift WWDC会话简介中,description演示了一个只读属性:

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

let vehicle = Vehicle()
println(vehicle.description)
Run Code Online (Sandbox Code Playgroud)

选择上述方法而不是使用方法有任何影响:

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

let vehicle = Vehicle()
println(vehicle.description())
Run Code Online (Sandbox Code Playgroud)

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

  • 语义 - 在这个例子中,成为description类的属性是有意义的,而不是它执行的动作.
  • 简洁/清晰 - 在获取值时无需使用空括号.

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


NB乍一看,这似乎是一个非常常见的OOP问题,但我很想知道任何特定于Swift的功能,这些功能可以指导使用这种语言时的最佳实践.

Joh*_*rug 51

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

当Apple发布一些Swift编码约定时,我们可能会更加清晰.


onm*_*133 12

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

在某些情况下,没有参数的函数可以与只读属性互换.尽管语义相似,但是对于何时优先选择彼此,存在一些风格约定.

在基础算法时首选属性而不是函数:

  • 不扔
  • 复杂度很便宜(或在第一次运行时计算)
  • 通过调用返回相同的结果


小智 11

虽然计算属性与方法的问题一般是困难和主观的,但目前在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)))
Run Code Online (Sandbox Code Playgroud)


ily*_* n. 7

由于运行时是相同的,因此该问题也适用于Objective-C.我会说,你得到的属性

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

至于特定于Swift的东西,我唯一的例子是你可以@lazy用于一个属性.


Ana*_*ile 7

有一点不同:如果使用属性,则最终可以覆盖它并使其在子类中进行读/写.

  • 您也可以覆盖功能.或者添加一个setter来提供写作能力. (9认同)

egn*_*nha 6

在只读情况下,计算出的属性应该被认为是语义上等同于一个方法,即使他们的行为相同,因为下降的func声明模糊包含量之间的区别状态的实例是仅仅和数量的功能的状态。您可以节省()在调用站点上的输入,但可能会使代码变得不清晰。

作为一个简单的例子,考虑以下向量类型:

struct Vector {
    let x, y: Double
    func length() -> Double {
        return sqrt(x*x + y*y)
    }
}
Run Code Online (Sandbox Code Playgroud)

通过将长度声明为方法,很明显它是状态的函数,它仅取决于xy

另一方面,如果您要表示length为计算属性

struct VectorWithLengthAsProperty {
    let x, y: Double
    var length: Double {
        return sqrt(x*x + y*y)
    }
}
Run Code Online (Sandbox Code Playgroud)

那么当你在你的IDE点选项卡完成上的一个实例VectorWithLengthAsProperty,它看起来好像xylength是平起平坐,这是不正确概念的属性。

  • 这很有趣,但是你能举一个例子来说明在遵循这个原则时_将_使用计算只读属性的地方吗?也许我错了,但您的论点似乎表明应该_永远_不要使用它们,因为根据定义,计算出的只读属性从不包含状态。 (6认同)