如何在Golang与Dart间传递结构体和函数?FFI调用结构体报错求助
Flutter FFI调用Go结构体返回值问题解决
问题概述
在Flutter应用中使用ffi调用Go编译的共享库时,GetKey和SumNumbers函数可正常调用,但调用GetPerson时触发错误:
Invalid argument(s): Failed to lookup symbol 'GetPerson': error code 127
核心原因
Go的-buildmode=c-shared编译模式仅支持导出符合C语言ABI的函数和类型:
- Go自定义结构体无法直接作为函数返回值被C识别,编译时不会生成对应导出符号,导致Dart找不到
GetPerson函数; - Go原生
string、int类型与C语言类型不兼容,直接使用会导致内存布局不匹配。
修正后的Go代码
将结构体改为C兼容类型,通过指针返回结构体实例,并添加内存释放函数避免泄漏:
package main import "C" import "unsafe" //export GetKey func GetKey() *C.char { theKey := "123-456-789" return C.CString(theKey) } //export SumNumbers func SumNumbers(a, b C.int) C.int { return a + b } //export GetPerson func GetPerson() *C.struct_Person { p := &C.struct_Person{ name: C.CString("name1"), age: C.int(20), job: C.CString("job1"), salary: C.int(100), } return p } //export FreePerson func FreePerson(p *C.struct_Person) { C.free(unsafe.Pointer(p.name)) C.free(unsafe.Pointer(p.job)) C.free(unsafe.Pointer(p)) } // 定义C兼容的Person结构体 type Person C.struct_Person func main() {}
修正后的Dart代码
对应Go的C结构体内存布局调整类型定义,修改函数签名为指针返回,并添加内存释放逻辑:
import 'dart:ffi'; import 'package:ffi/ffi.dart'; // 与Go中C兼容Person结构体内存布局完全匹配 class Person extends Struct { external Pointer<Utf8> name; @Int32() external int age; external Pointer<Utf8> job; @Int32() external int salary; } // 函数类型定义 typedef GetPersonC = Pointer<Person> Function(); typedef GetPersonDart = Pointer<Person> Function(); typedef FreePersonC = Void Function(Pointer<Person>); typedef FreePersonDart = void Function(Pointer<Person>); void main() { // 加载共享库(根据平台调整路径:Windows用.dll,macOS用.dylib,Linux用.so) final dylib = DynamicLibrary.open('lib.a'); // 查找导出函数 final getPerson = dylib.lookupFunction<GetPersonC, GetPersonDart>('GetPerson'); final freePerson = dylib.lookupFunction<FreePersonC, FreePersonDart>('FreePerson'); // 获取Person指针并读取字段 final personPtr = getPerson(); final name = personPtr.ref.name.toDartString(); final age = personPtr.ref.age; final job = personPtr.ref.job.toDartString(); final salary = personPtr.ref.salary; print('Name: $name, Age: $age, Job: $job, Salary: $salary'); // 释放内存,避免泄漏 freePerson(personPtr); }
关键注意事项
- 类型严格匹配:Dart Struct的字段类型必须与Go中C结构体内存布局完全一致,例如Go的
C.int对应Dart的@Int32(); - 内存手动管理:Go中
C.CString分配的内存需通过自定义释放函数在Dart中调用释放; - 平台适配编译:根据目标平台调整编译输出后缀:
# Windows go build -buildmode=c-shared -o lib.dll lib.go # macOS go build -buildmode=c-shared -o lib.dylib lib.go # Linux go build -buildmode=c-shared -o lib.so lib.go
内容的提问来源于stack exchange,提问作者Masoud
相关产品推荐
相关产品推荐

