问题描述
class Foo {
let closure: ()->()
func someFunc() {}
init(closure: @escaping ()->()) {
self.closure = closure
}
}
class Bar {
lazy var foo = Foo { [weak self] in // Circular Reference error here!
self?.foo.someFunc()
}
}
但是,如果我将其更改为:
class Bar {
lazy var foo: Foo = {
return Foo { [weak self] in
self?.foo.someFunc()
}
}()
}
那么就没有循环引用错误了。
解决方法
问题在这里:
lazy var foo = Foo { [weak self] in
self.foo.someFunc()
} // ^^^
所以您是根据 foo
定义 foo
。那是一个圆圈。跟说没区别
lazy var foo = self.foo
很明显是圆形的。
当您将整个事物包装在一个评估级别({...}()
构造)中时,对 self.foo
的内部引用保证不会在以后评估。
更新:
循环引用在类型推断中:foo
的类型取决于self.foo
的类型,foo
的类型取决于self.foo
的类型,而class Bar {
lazy var foo: Foo = Foo { [weak self] in
self?.foo.someFunc()
}
}
的类型取决于Bar
的类型等。
上一个答案:
我想我在这里找到了根本原因(感谢我的一些同事!):
我的同事注意到这段代码编译得很好,这指出它可能是类型推断问题。我被包装封口甩了,这显然与真正的问题无关。
foo
我认为为了让编译器评估 self
,它必须对属性 Bar
进行类型推断,这需要编译器评估属性初始化代码。然而,属性初始化代码本身包含对 Bar
/template<class Float>
struct Number {
Float v;
Number(Float iv = 0) : v(iv) {}
};
template<class F>
Number<F> operator+(Number<F> const& a,Number<F> const& b) {
return {a.v + b.v};
}
int main() {
Number<float> y = Number<float>(1) + 2.0f;
std::cout << y.v << "\n";
}
的引用,因此为了评估该代码,必须首先评估 main.cpp:15:38: error: invalid operands to binary expression ('Number<float>' and
'float')
Number<float> y = Number<float>(1) + 2.0f;
~~~~~~~~~~~~~~~~ ^ ~~~~
main.cpp:10:11: note: candidate template ignored: could not match
'Number<type-parameter-0-0>' against 'float'
Number<F> operator+(Number<F> const& a,Number<F> const& b) {
^
。因此循环引用。