为什么捕获列表中的捕获说明符是可选的?
Why is the capture specifier optional in capture lists?
Swift 中的捕获列表语法中似乎存在一个奇怪的语法错误。如果我声明了多个捕获变量,则捕获说明符仅适用于第一个变量:
let closure = { [unowned x, y] in … }
现在我希望 y
是 unowned
,但似乎并非如此:
class Test {
var callback: (Void -> Void)?
init() {
print("init")
}
deinit {
print("deinit")
}
}
func makeScope() {
let x = Test()
let y = Test()
y.callback = { [unowned x, y] in
print(y)
}
}
makeScope()
print("done")
这会打印:
init
init
deinit
done
所以y
似乎被强捕获并创建了一个保留循环,阻止了对象被释放。是这样吗?如果是,在列表中允许“空”捕获说明符是否有意义?或者有什么原因 [unowned x, y]
不被视为 [unowned x, unowned y]
?
根据 syntax EBNF,unowned
捕获说明符 的这种处理是完全有意的:
closure-signature → parameter-clause function-resultopt in
closure-signature → identifier-list function-resultopt in
closure-signature → capture-list parameter-clause function-resultopt in
closure-signature → capture-list identifier-list function-resultopt in
closure-signature → capture-list in
capture-list → [capture-list-items]
capture-list-items → capture-list-item capture-list-item ,
capture-list-items
capture-list-item → capture-specifieropt expression
capture-specifier → weak
| unowned
| unowned(safe)
| unowned(unsafe)
定义 <capture-list-items>
、<capture-list-item>
和 <capture-specifier>
产品的底部三行在这里最相关。
<capture-list-items>
产生式是 <capture-list-item>
的逗号分隔列表,capture-specifier
附加到每个 <capture-list-item>
,而不是 <capture-list-items>
整体列出。
这很有意义,因为它使程序员可以完全控制对单个参数的捕获。当说明符应用于整个列表时的替代方案将取消这种灵活性。
why would one want to include an identifier in the capture list without modifying its capture specifier?
看来 Swift 的设计者的理念是尽可能提供智能默认行为。在大多数情况下,Swift 可以根据表达式的类型找到一种捕获最有意义的表达式的方法,而无需程序员参与。当编译器没有足够的信息来找出基于上下文捕获变量的正确方法时,显式捕获说明符用于特殊情况。
... does it make sense to permit an “empty” capture specifier in the list?
是的。
捕获说明符("weak"、"unowned" 及其变体)只能与 引用类型 一起使用,但也有一些情况需要捕获 值类型
(这里是一个例子:
).
您可能还想强捕获引用类型。
捕获引用类型确保引用(指针)
本身是按值捕获的,如以下示例所示:
class MyClass {
let value : String
init(value : String) {
self.value = value
}
}
var ref = MyClass(value: "A")
let clo1: () -> Void = { print(ref.value) }
let clo2: () -> Void = { [ref] in print(ref.value) }
ref = MyClass(value: "B")
clo1() // Output: B
clo2() // Output: A
当第一个闭包执行时,ref
闭包内部
是对创建为 MyClass(value: "B")
.
的对象的引用
第二个闭包捕获 ref
的值
关闭被创建,并且当一个新值时这不会改变
分配给 var ref
.
回答您的具体问题:
Why is the capture specifier optional in capture lists?
因为默认行为是捕获任何必要的变量(强烈捕获引用类型)。默认情况下,如果要使用它们的值,则无需在捕获列表中明确指定它们。 (尽管如果您要捕获 self
,则需要使用 self.property
进行资格赛。)
…is there a reason [unowned x, y]
is not treated as [unowned x, unowned y]
?
同理:默认是强捕获。 unowned
不适用于捕获列表中的其他项目;这不是现在语法的工作方式。
Swift 中的捕获列表语法中似乎存在一个奇怪的语法错误。如果我声明了多个捕获变量,则捕获说明符仅适用于第一个变量:
let closure = { [unowned x, y] in … }
现在我希望 y
是 unowned
,但似乎并非如此:
class Test {
var callback: (Void -> Void)?
init() {
print("init")
}
deinit {
print("deinit")
}
}
func makeScope() {
let x = Test()
let y = Test()
y.callback = { [unowned x, y] in
print(y)
}
}
makeScope()
print("done")
这会打印:
init
init
deinit
done
所以y
似乎被强捕获并创建了一个保留循环,阻止了对象被释放。是这样吗?如果是,在列表中允许“空”捕获说明符是否有意义?或者有什么原因 [unowned x, y]
不被视为 [unowned x, unowned y]
?
根据 syntax EBNF,unowned
捕获说明符 的这种处理是完全有意的:
closure-signature → parameter-clause function-resultopt
in
closure-signature → identifier-list function-resultoptin
closure-signature → capture-list parameter-clause function-resultoptin
closure-signature → capture-list identifier-list function-resultoptin
closure-signature → capture-listin
capture-list → [capture-list-items]
capture-list-items → capture-list-item capture-list-item,
capture-list-items
capture-list-item → capture-specifieropt expression
capture-specifier →weak
|unowned
|unowned(safe)
|unowned(unsafe)
定义 <capture-list-items>
、<capture-list-item>
和 <capture-specifier>
产品的底部三行在这里最相关。
<capture-list-items>
产生式是 <capture-list-item>
的逗号分隔列表,capture-specifier
附加到每个 <capture-list-item>
,而不是 <capture-list-items>
整体列出。
这很有意义,因为它使程序员可以完全控制对单个参数的捕获。当说明符应用于整个列表时的替代方案将取消这种灵活性。
why would one want to include an identifier in the capture list without modifying its capture specifier?
看来 Swift 的设计者的理念是尽可能提供智能默认行为。在大多数情况下,Swift 可以根据表达式的类型找到一种捕获最有意义的表达式的方法,而无需程序员参与。当编译器没有足够的信息来找出基于上下文捕获变量的正确方法时,显式捕获说明符用于特殊情况。
... does it make sense to permit an “empty” capture specifier in the list?
是的。
捕获说明符("weak"、"unowned" 及其变体)只能与 引用类型 一起使用,但也有一些情况需要捕获 值类型
(这里是一个例子:
您可能还想强捕获引用类型。 捕获引用类型确保引用(指针) 本身是按值捕获的,如以下示例所示:
class MyClass {
let value : String
init(value : String) {
self.value = value
}
}
var ref = MyClass(value: "A")
let clo1: () -> Void = { print(ref.value) }
let clo2: () -> Void = { [ref] in print(ref.value) }
ref = MyClass(value: "B")
clo1() // Output: B
clo2() // Output: A
当第一个闭包执行时,ref
闭包内部
是对创建为 MyClass(value: "B")
.
第二个闭包捕获 ref
的值
关闭被创建,并且当一个新值时这不会改变
分配给 var ref
.
回答您的具体问题:
Why is the capture specifier optional in capture lists?
因为默认行为是捕获任何必要的变量(强烈捕获引用类型)。默认情况下,如果要使用它们的值,则无需在捕获列表中明确指定它们。 (尽管如果您要捕获 self
,则需要使用 self.property
进行资格赛。)
…is there a reason
[unowned x, y]
is not treated as[unowned x, unowned y]
?
同理:默认是强捕获。 unowned
不适用于捕获列表中的其他项目;这不是现在语法的工作方式。