Lambda 对代理和闭包在Vala中的行为感到困惑
我创建了一个最小的示例,它再现了一种奇怪的Vala行为,我不理解,我想解释一下 类Lambda 对代理和闭包在Vala中的行为感到困惑,lambda,vala,Lambda,Vala,我创建了一个最小的示例,它再现了一种奇怪的Vala行为,我不理解,我想解释一下 类Test的构造函数获取一个Func并使用它初始化其类成员f: public class Test { public delegate int Func(); public static Func FUNC_0 = () => { return 0; }; public Func f; public Test( Func f ) { this.f =
Test
的构造函数获取一个Func
并使用它初始化其类成员f
:
public class Test
{
public delegate int Func();
public static Func FUNC_0 = () => { return 0; };
public Func f;
public Test( Func f )
{
this.f = f; // line 10
}
}
我使用Test.Func\u 0
中定义的Func
实例化Test
对象,并执行一些测试:
public static void main()
{
assert( Test.FUNC_0 != null ); // first assert
var t = new Test( Test.FUNC_0 );
assert( t.f != null ); // second assert
}
这有什么奇怪的
- 首先,事实证明,
是Test.FUNC\u 0
。怎么会这样李>null
给了我一个警告,“不支持复制委托”,但是在第10行,这是valac
赋值,因此此警告不考虑this.f=f
字段Test.FUNC\u 0
- 如果删除第一个
,并将断言
的新测试
参数替换为Test.FUNC\u 0
,则第二个()=>{return 0;}
通过。那么第10行中的这个.f=f有什么问题?第10行的闭包是否已复制断言
- 如果是,我将如何调整代码,使其仅保留一个引用作为
中的类成员Test
我真的很高兴看到解释。valac的版本是0.28.1。您的问题实际上与委托无关,而与单独拥有的实例有关。Vala中的所有非原语类型都是有主类型或无主类型。某些类(包括从
GLib.Object
派生的类)可以有多个所有者。当需要类的副本时,目标类上的引用计数将递增。其他类(包括string
)和结构只能有一个所有者,但附带了一个复制函数,允许生成该类的副本。委托和某些类(如FileStream
)也只有一个所有者,但不能复制
无法复制委托的原因是委托包含三条信息:回调函数、一些上下文数据,以及上下文数据的析构函数。没有复制功能
由于默认情况下参数是无主的,this.f=f
正试图将它不拥有的委托复制到它拥有的引用中。这将是内存不安全的,因为它要么在对象的生命周期之后保存引用,要么可以调用析构函数两次
您有两个选择:
public class Test
{
public delegate int Func();
public static Func FUNC_0 = () => { return 0; };
public Func f;
public Test( owned Func f )
{
this.f = (owned) f; // you are just moving the delegate, not copying it.
}
}
或者:
public class Test
{
public delegate int Func();
public static Func FUNC_0 = () => { return 0; };
public unowned Func f;
public Test( Func f )
{
this.f = f; // You are copying an unowned reference to another
// unowned reference, which is fine. Memory management is now your
// job and not Vala's.
}
}
第二个有点危险。例如,以下代码将编译并损坏内存:
Test? t = null;
if (true) {
int x = 5;
Func f = () => { return x; };
t = new Test(f);
}
t.f();