您好我正在使用qml库去创建UI。我正在尝试学习如何从UI(qml)传递信息然后去做"做某事"用。 如果它只是一个UI,QML就可以了。我这样做的时候能跑得很好:
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "usage: %s <qml file>\n", os.Args[0])
os.Exit(1)
}
if err := qml.Run(run); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}
func run() error {
engine := qml.NewEngine()
engine.On("quit", func() { os.Exit(0) })
component, err := engine.LoadFile(os.Args[1])
if err != nil {
return err
}
window := component.CreateWindow(nil)
window.Show()
window.Wait()
return nil
}
然而,当我添加一些代码时,尝试&#34;学习&#34;来自UI的东西我得到了运行时错误:
恐慌:运行时错误:cgo参数有Go指针指向Go指针
我要添加的代码是:
window.On("visibleChanged", func(visible bool) {
if (visible) {
fmt.Println("Width:", window.Int("width"))
}
})
我正在跑步&#34;去版本go1.6 darwin / amd64&#34;在OSX El Capitan上
任何想法为什么?谷歌建议这是Go 1.6 Beta中的一个错误,但我正在运行最新的稳定版本(几天前安装)。
如果它不是一个简单的解决方案,有人可以解释&#34;为什么&#34;这是发生了吗?
答案 0 :(得分:6)
问题是,当C代码存储Go指针(在这种情况下,指向回调函数的指针)时,垃圾收集器无法跟踪C代码中的指针,并且可能垃圾收集指针指向的内存如果没有Go代码引用它。这将导致C代码在尝试访问该内存时崩溃。所有运行时都知道C代码保留了指针(这就是为什么它可以发生恐慌),但是它不知道C代码将在以后用它做什么以及它将保留多长时间。
为了避免这种情况,大多数库使用的技巧是在Go中保持指针(例如在全局映射中),以确保内存受到垃圾收集器的保护。 go-qml使用this trick as well。这个技巧有效,但编译器和垃圾收集器不知道它确实存在,它们无法验证您是否犯了错误(例如,删除Go指针,而C代码仍有其指针)。
使用Go 1.6,Go开发人员决定对此非常严格,并且他们不再允许C代码保留Go指针。但是,如果禁用此检查,在这种情况下一切都仍然有效,因为go-qml正确实现了这一技巧(但是将来可能会中断,例如,如果go实现移动垃圾收集器)。
以下是关于它的问题:https://github.com/go-qml/qml/issues/170
附注:在这种特定情况下,传递给C的是指向interface{}
的指针,public class MainActivity extends AppCompatActivity {
private FragmentManager manager;
private android.support.v4.app.FragmentTransaction transaction;
private Socket socket;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
manager = getSupportFragmentManager();
transaction = manager.beginTransaction();
chatFragment enter = new chatFragment();
transaction.add(R.id.fragmentContainer, enter);
transaction.commit();
}
}
}
本身包含指向函数的指针。这就是为什么你得到错误&#34; cgo参数有Go指针指向Go指针&#34;。这是不允许的原因是在C调用期间保护这些指针更难以保存,并且它不值得,所以它是被禁止的相反(https://github.com/golang/go/issues/12416#issuecomment-136473697)。
但是,即使允许这样做,代码仍然会违反关于C代码保留Go指针副本的规则。
这在Go 1.6中实际上不是问题,因为它没有实现移动的垃圾收集器,但规则是为了以后可以实现。
答案 1 :(得分:1)
如果你只是在玩耍,我建议尝试去1.5.3。在使用cgo时,Go 1.6对内存指针引入了一组不同的约束,这是一个限制性更强的集合,并且为旧版本的go设计的一些go包现在可以打破一两个规则。
如果是这种情况,让旧版软件包与1.6一起使用,其中C允许调用go闭包,可能更难修复。但我还没有第一手经验。
答案 2 :(得分:-2)
感谢您提供的所有帮助。我已经写了一篇关于在Go上使用QML的初学者教程。它可以在这里查看。如果我遇到更多错误并找到修复程序,我会不断更新它。谢谢大家的帮助。 QML / GO是一个很棒的组合。