[英]Why does this closure code throw an error when not using a capture list?
func biggerOne(_ a : Int, _ b : Int) -> Int? {
if a == b {
return nil
} else if a > b {
return a
} else {
return b
}
}
var someClosure : (Int, Int) -> Int? = biggerOne(_:_:)
// Not working
someClosure = { (left : Int, right : Int) in
someClosure(left , right)
}
print(someClosure(2,3)!)
// Working
someClosure = { [someClosure] (left : Int, right : Int) in
someClosure(left , right)
}
print(someClosure(2,3)!)
I knew that closure uses capture list to store values on creation so can solve the problem but why is the code above not working?我知道闭包使用捕获列表来存储创建时的值,因此可以解决问题,但为什么上面的代码不起作用?
If you have any ideas, I would appreciate your help.如果您有任何想法,我将不胜感激您的帮助。
There are circular references, someClosure
is calling itself.有循环引用,
someClosure
在调用自己。
Try eliminating the circular references:尝试消除循环引用:
// Now it works
let firstClosure = { (left : Int, right : Int) in
someClosure(left , right)
}
print(firstClosure(2,3)!)
// Working
let secondClosure = { [someClosure] (left : Int, right : Int) in
someClosure(left , right)
}
print(secondClosure(2,3)!)
Without capturing, someClosure
here is simply calling itself, and then causing a stack overflow:没有捕获,这里的
someClosure
只是简单地调用自己,然后导致堆栈溢出:
someClosure = { (left : Int, right : Int) in
someClosure(left , right) // this call refers to the new value of "someClosure"
}
(I'm not sure if the fact that this passes compilation is intentional.) (我不确定这个通过编译的事实是否是故意的。)
This is just like as if you have defined a named function like:这就像您定义了一个名为 function 的名称一样:
func someClosure(left: Int, right: Int): Int? {
someClosure(left: left, right: right)
}
On the other hand, the capture list captures the old value of someClosure
, so " someClosure
" inside the closure body refers to the captured value (ie the old value), and there is no infinite recursion.另一方面,捕获列表捕获了
someClosure
的旧值,所以闭包体内的“ someClosure
”指的是捕获的值(即旧值),不存在无限递归。 You can think of this as:您可以将其视为:
let captured = someClosure
someClosure = { (left : Int, right : Int) in
captured(left , right)
}
Using lldb yourExecutable
and the thread backtrace
command, you can see the many duplicated stack frames that are caused by the recursion.使用
lldb yourExecutable
和thread backtrace
命令,您可以看到递归导致的许多重复堆栈帧。
(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7ff7bf6ffff8)
* frame #0: 0x00007ff822e4fa99 libswiftCore.dylib`swift_beginAccess + 41
frame #1: 0x0000000100003d87 yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 71
frame #2: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #3: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #4: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
...
frame #65515: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #65516: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #65517: 0x0000000100003baa yourExecutable`main + 218
frame #65518: 0x00000001000154fe dyld`start + 462
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.