subscript
和callAsFunction
之间有什么区别?在我看来,它们的行为几乎相同,它们都可以有参数标签、默认值等。
除了subscript
使用方括号instance[index]
,callAsFunction
使用圆括号instance(index)
,它们之间是否有任何实际区别呢?
顺便说一下,我们知道subscript
可以有一个setter,那么callAsFunction
呢?它也可以有setter吗?
subscript
和callAsFunction
之间有什么区别?在我看来,它们的行为几乎相同,它们都可以有参数标签、默认值等。
除了subscript
使用方括号instance[index]
,callAsFunction
使用圆括号instance(index)
,它们之间是否有任何实际区别呢?
顺便说一下,我们知道subscript
可以有一个setter,那么callAsFunction
呢?它也可以有setter吗?
通过getter和setter方法,可以将下标设置为读写或只读。callAsFunction()是一种允许您具有参数执行某些步骤或函数的方法。
查看Swift文档中的下标,我们可以看到如下内容。
Source: https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html
subscript(index: Int) -> Int {
get {
// Return an appropriate subscript value here.
}
set(newValue) {
// Perform a suitable setting action here.
}
}
callAsFunction()
的调用没有getter和setter。你可能会有像这样返回计算值的内容。
来源: https://www.hackingwithswift.com/articles/212/whats-new-in-swift-5-2
struct StepCounter {
var steps = 0
mutating func callAsFunction(count: Int) -> Bool {
steps += count
print(steps)
return steps > 10_000
}
}
var steps = StepCounter()
let targetReached = steps(count: 10)
让我们使用这里的示例:
struct Dice {
var lowerBound: Int
var upperBound: Int
func callAsFunction() -> Int {
(lowerBound...upperBound).randomElement()!
}
}
let d6 = Dice(lowerBound: 1, upperBound: 6)
let roll1 = d6()
print(roll1)
想象一下,如果这个用下标写会是什么样子:
subscript() -> Int {
(lowerBound...upperBound).randomElement()!
}
let roll1 = d6[]
这段代码可以运行,但是d6[]
并不能像d6()
那样准确地表达“掷骰子”的意思。使用d6[]
的感觉更像是在访问d6
中的某个元素。
相反,想象一下如果字典访问也像函数调用一样:
let studentScores = ["Tom": 100, "Jack": 80, "Harry", 70]
let tomsScore = studentScores("Tom")
感觉我正在执行一个名为studentScores
的操作。如果我将字典重命名为studentScoresFor
会更好,但这对于一个字典来说是一个奇怪的名称...
方法和下标目前具有不同的功能。但它们正在趋同。(例如,下标获得了泛型/静态,而callAsFunction
使用与下标相同的语法。)
现在没有理由让它们同时存在。它们来自于Swift之前的时代。任何认为它们具有固有不同含义的人只是因为他们学习了它并且现在觉得它“自然”。要警惕教条主义。
目前,如果您想在等号后使用值,则需要使用下标。如果此功能最终被纳入Swift中,它可能会以“命名下标”的形式出现。一旦人们习惯了这种方式,您将看到更多像您一样的人开始提出问题。
然后,其中一个语法将被弃用,或者我们将等待Swift的继任者。
以下是命名下标的示例:
final class Class {
var bools: ObjectSubscript<Class, String, Bool?> {
.init(
self,
get: { object in
{ object._bools[$0]
?? Bool(binaryString: $0)
}
},
set: { $0._bools[$1] = $2 }
)
}
private var _bools: [String: Bool] = [:]
}
let object = Class()
let ghoul = ""
XCTAssertEqual(object.bools["1"], true)
XCTAssertNil(object.bools[ghoul])
object.bools[ghoul] = false
XCTAssertEqual(object.bools[ghoul], false)
/// An emulation of the missing Swift feature of named subscripts.
/// - Note: Argument labels are not supported.
public struct ObjectSubscript<Object: AnyObject, Index, Value> {
public typealias Get = (Object) -> (Index) -> Value
public typealias Set = (Object, Index, Value) -> Void
public unowned var object: Object
public var get: Get
public var set: Set
}
public extension ObjectSubscript {
init(
_ object: Object,
get: @escaping Get,
set: @escaping Set
) {
self.object = object
self.get = get
self.set = set
}
subscript(index: Index) -> Value {
get { get(object)(index) }
nonmutating set { set(object, index, newValue) }
}
}
var set: Set = [1, 2, 3]
XCTAssert(set.contains[3])
set.contains[1] = false
XCTAssertEqual(set, [2, 3])
var contains = set.contains
contains[3].toggle()
XCTAssertEqual(set, [2])
contains.set = { _, _, _ in }
contains[2].toggle()
XCTAssertEqual(set, [2])
var four: Set = [4]
withUnsafeMutablePointer(to: &four) {
contains.pointer = $0
XCTAssert(contains[4])
}
public extension SetAlgebra {
var contains: ValueSubscript<Self, Element, Bool> {
mutating get {
.init(
&self,
get: Self.contains,
set: { set, element, newValue in
if newValue {
set.insert(element)
} else {
set.remove(element)
}
}
)
}
}
}
/// An emulation of the missing Swift feature of named subscripts.
/// - Note: Argument labels are not supported.
public struct ValueSubscript<Root, Index, Value> {
public typealias Pointer = UnsafeMutablePointer<Root>
public typealias Get = (Root) -> (Index) -> Value
public typealias Set = (inout Root, Index, Value) -> Void
public var pointer: Pointer
public var get: Get
public var set: Set
}
public extension ValueSubscript {
init(
_ pointer: Pointer,
get: @escaping Get,
set: @escaping Set
) {
self.pointer = pointer
self.get = get
self.set = set
}
subscript(index: Index) -> Value {
get { get(pointer.pointee)(index) }
nonmutating set { set(&pointer.pointee, index, newValue) }
}
}
callAsFunction
语法糖和下标,即someObject[xxx]
vssomeObject(xxx)
。只有你的第二段似乎试图回答这个问题。 - Sweeper