如何在闭包中捕获一个 int 值?
How to capture an int value in a closure?
我有一个包含任意数量元素的应用程序,所有这些元素都调用一个需要接受参数的函数,该参数在创建时定义。这是一个简化的示例,但在这里我希望制作 3 个打印 0、1、2 的按钮,但只制作 3 个打印 3 的按钮。
var application_window = new Gtk.ApplicationWindow (this);
var grid = new Gtk.Grid ();
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(i.to_string());
});
grid.add(button);
}
application_window.add(grid);
application_window.show_all ();
如何更改我的应用程序以改为打印 123?
这是我的基本代码:
public class MyApplication : Gtk.Application {
public MyApplication () {
Object(application_id: "testing.my.application",
flags : ApplicationFlags.FLAGS_NONE);
}
protected override void activate () {
var application_window = new Gtk.ApplicationWindow (this);
var grid = new Gtk.Grid ();
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(i.to_string());
});
grid.add(button);
}
application_window.add(grid);
application_window.show_all ();
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
return app.run (args);
}
}
如果你这样执行它,你会得到 333
作为标准输出。
问题出在捕获代码中:
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(i.to_string());
});
闭包正在按位置捕获变量 i。这意味着当您在创建闭包后更改 i 变量时,更改也会在闭包中可见。
其他编程语言(例如 C++)有明确的捕获列表来避免这个问题。
一个快速而肮脏的解决方案是在循环范围内使用局部变量:
for (int i = 0; i < 3; i++) {
var captured_i = i;
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(captured_i.to_string());
});
这将按预期打印:012
。
更好的解决方案是使用 returns 闭包作为委托的函数。我刚刚试过了,但由于某种原因它不起作用:
public class MyApplication : Gtk.Application {
public MyApplication () {
Object(application_id: "testing.my.application",
flags : ApplicationFlags.FLAGS_NONE);
}
delegate void ButtonClick();
private ButtonClick make_print_event (int i) {
return () => print (i.to_string());
}
protected override void activate () {
var application_window = new Gtk.ApplicationWindow (this);
var grid = new Gtk.Grid ();
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() { expand=true };
var print_event = make_print_event (i);
button.clicked.connect (print_event);
grid.add(button);
}
application_window.add (grid);
application_window.show_all ();
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
return app.run (args);
}
}
编译器 (valac-0.52) 警告:
three_buttons.vala:20.37-20.47: warning: copying delegates is not supported
three_buttons.vala:20.37-20.47: warning: Connecting delegates to signals is experimental
button.clicked.connect (print_event);
^^^^^^^^^^^
我有一个包含任意数量元素的应用程序,所有这些元素都调用一个需要接受参数的函数,该参数在创建时定义。这是一个简化的示例,但在这里我希望制作 3 个打印 0、1、2 的按钮,但只制作 3 个打印 3 的按钮。
var application_window = new Gtk.ApplicationWindow (this);
var grid = new Gtk.Grid ();
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(i.to_string());
});
grid.add(button);
}
application_window.add(grid);
application_window.show_all ();
如何更改我的应用程序以改为打印 123?
这是我的基本代码:
public class MyApplication : Gtk.Application {
public MyApplication () {
Object(application_id: "testing.my.application",
flags : ApplicationFlags.FLAGS_NONE);
}
protected override void activate () {
var application_window = new Gtk.ApplicationWindow (this);
var grid = new Gtk.Grid ();
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(i.to_string());
});
grid.add(button);
}
application_window.add(grid);
application_window.show_all ();
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
return app.run (args);
}
}
如果你这样执行它,你会得到 333
作为标准输出。
问题出在捕获代码中:
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(i.to_string());
});
闭包正在按位置捕获变量 i。这意味着当您在创建闭包后更改 i 变量时,更改也会在闭包中可见。
其他编程语言(例如 C++)有明确的捕获列表来避免这个问题。
一个快速而肮脏的解决方案是在循环范围内使用局部变量:
for (int i = 0; i < 3; i++) {
var captured_i = i;
var button = new Gtk.Button() {expand=true};
button.clicked.connect (() => {
print(captured_i.to_string());
});
这将按预期打印:012
。
更好的解决方案是使用 returns 闭包作为委托的函数。我刚刚试过了,但由于某种原因它不起作用:
public class MyApplication : Gtk.Application {
public MyApplication () {
Object(application_id: "testing.my.application",
flags : ApplicationFlags.FLAGS_NONE);
}
delegate void ButtonClick();
private ButtonClick make_print_event (int i) {
return () => print (i.to_string());
}
protected override void activate () {
var application_window = new Gtk.ApplicationWindow (this);
var grid = new Gtk.Grid ();
for (int i = 0; i < 3; i++) {
var button = new Gtk.Button() { expand=true };
var print_event = make_print_event (i);
button.clicked.connect (print_event);
grid.add(button);
}
application_window.add (grid);
application_window.show_all ();
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
return app.run (args);
}
}
编译器 (valac-0.52) 警告:
three_buttons.vala:20.37-20.47: warning: copying delegates is not supported
three_buttons.vala:20.37-20.47: warning: Connecting delegates to signals is experimental
button.clicked.connect (print_event);
^^^^^^^^^^^