英文:
How do I provide access to the library I wrap with cgo?
问题
我正在尝试为一个C库编写绑定,具体来说是libnfc。我的当前代码可以在Github上找到。
libnfc中的一个核心结构是设备(device)。它由Go类型Device
表示。
type Device struct {
d *C.nfc_device
}
libnfc中的所有操作Device
的函数都是它的方法。现在,还有其他的C库(例如libfreefare)其API操作的是nfc_device
。为了模块化,我希望将每个我封装的库的代码放在自己的模块中。这就导致了一个问题,我无法从其他模块中访问私有结构成员。我考虑了以下解决方案:
-
将
d
作为Device
的公共成员这样可以轻松地从其他模块中访问底层的
nfc_device
,但也容易绕过类型安全。此外,我不知道cgo是否能够识别来自不同模块的外部类型的指针。最后,如果我更改Device
类型的结构,我会失去灵活性。 -
添加一个访问器
func (Device) GetCPtr() unsafe.Pointer
这解决了上述问题,但引入了一个新问题,即在可能甚至不导入
unsafe
的模块中,你突然可以访问一个unsafe.Pointer
。 -
添加一个访问器
func (Device) GetCPtr() uintptr
这解决了上述问题,因为你必须手动转换结果以获得正确的指针。
还有其他我忽略的方法吗?有没有更好、更符合惯例的方法来访问底层的nfc_device
?
英文:
I am trying to write bindings for a C library, specifically the libnfc. My current code is available on Github.
One of the central structures in the libnfc is the device. It is represented by the Go type Device
.
type Device struct {
d *C.nfc_device
}
All functions inside the libnfc that operate on a Device
are methods of it. Now, there are other C libraries (e.g. the libfreefare) whose APIs operates on nfc_device
es. For the sake of modularity, I want to place the code for each library I wrap into its own module. This leads to the problem, that I can't access private structure members from within other modules. I thought about the following solutions:
-
Make
d
a public member ofDevice
This would make it easy to access the underlying
nfc_device
from within other modules, but it makes it also easy to sidestep type safety. Additionally, I don't know whether cgo recognizes pointers to foreign types if they come from different modules. Finally, I lose flexibility if I change the structure of the Device type. -
Add an accessor
func (Device) GetCPtr() unsafe.Pointer
This solves the issues above but introduces the new issue that you suddently have access to an
unsafe.Pointer
in a module that might not even importunsafe
. -
Add an accessor
func (Device) GetCPtr() uintptr
This solves the aforementioned issue, as you have to manually cast the result to get a proper pointer.
Are there any ways I missed? Is there a better, more idiomatic way to provide access to the underlying nfc_device
?
答案1
得分: 1
我一般支持你的第三个提议,因为这是reflect
包处理这个问题的方式。
你还可以在你的libnfc包装器中只公开一个接口,例如:
type NFCDevice interface {
Read() ([]byte, error)
Write() ([]byte, error)
// ...
}
现在你有一个安全的公共API。
此外,你的device
类型实现了一个函数:
func (d *device) NfcDevice() *C.nfc_device {
return d.nfc_device
}
你可以在其他包装器中使用这个函数,通过断言你的NFCDevice
实现接口:
interface {
NfcDevice() *C.nfc_device
}
你可以在其他包装器中即时创建这个接口。这样一来,程序员必须有意识地做一些事情才能访问你的device
的内部工作方式。
英文:
I'm generally in favour with the third proposal of yours as this is the way the reflect
package
handles this issue.
What you could also do is to expose only an interface in your libnfc wrapper, e.g.
type NFCDevice interface {
Read() ([]byte, error)
Write() ([]byte, error)
// ...
}
Now you have a public API that is safe.
Additionally, your device
type implements a function
func (d *device) NfcDevice() *C.nfc_device {
return d.nfc_device
}
which you can use in your other wrappers by asserting your NFCDevice
to implement the
interface
interface {
NfcDevice() *C.nfc_device
}
which you can create on the fly in the other wrappers. This way a programmer has to deliberately
do something to access the inner workings of your device
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论