diff --git a/ch2-cgo/ch2-03-cgo-types.md b/ch2-cgo/ch2-03-cgo-types.md index 47584bd..fb5ccec 100644 --- a/ch2-cgo/ch2-03-cgo-types.md +++ b/ch2-cgo/ch2-03-cgo-types.md @@ -1,6 +1,6 @@ # 2.3 类型转换 -最初CGO是为了达到方便从Go语言函数调用C语言函数以复用C语言资源这一目的而出现的(因为C语言还会涉及回调函数,自然也会涉及到从C语言函数调用Go语言函数)。现在,它已经演变为C语言和Go语言双向通讯的桥梁。要想利用好CGO特性,自然需要了解此二语言类型之间的转换规则,这是本节要讨论的问题。 +最初CGO是为了达到方便从Go语言函数调用C语言函数(用C语言实现Go语言声明的函数)以复用C语言资源这一目的而出现的(因为C语言还会涉及回调函数,自然也会涉及到从C语言函数调用Go语言函数(用Go语言实现C语言声明的函数))。现在,它已经演变为C语言和Go语言双向通讯的桥梁。要想利用好CGO特性,自然需要了解此二语言类型之间的转换规则,这是本节要讨论的问题。 ## 2.3.1 数值类型 @@ -71,7 +71,7 @@ typedef struct { void *t; void *v; } GoInterface; typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; ``` -不过需要注意的是,其中只有字符串和切片在CGO中有一定的使用价值,因为此二者可以在Go调用C语言函数时马上使用;而CGO并未针对其他的类型提供相关的辅助函数,且Go语言特有的内存模型导致我们无法保持这些由Go语言管理的内存指针,所以它们C语言环境并无使用的价值。 +不过需要注意的是,其中只有字符串和切片在CGO中有一定的使用价值,因为CGO为他们的某些GO语言版本的操作函数生成了C语言版本,因此二者可以在Go调用C语言函数时马上使用;而CGO并未针对其他的类型提供相关的辅助函数,且Go语言特有的内存模型导致我们无法保持这些由Go语言管理的内存指针,所以它们C语言环境并无使用的价值。 在导出的C语言函数中我们可以直接使用Go字符串和切片。假设有以下两个导出函数: @@ -364,7 +364,7 @@ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; 在Go语言中两个指针的类型完全一致则不需要转换可以直接通用。如果一个指针类型是用type命令在另一个指针类型基础之上构建的,换言之两个指针底层是相同完全结构的指针,那么我我们可以通过直接强制转换语法进行指针间的转换。但是cgo经常要面对的是2个完全不同类型的指针间的转换,原则上这种操作在纯Go语言代码是严格禁止的。 -cgo存在的一个目的就是打破Go语言的禁制,恢复C语言应有的指针的自由转换和指针运算。以下代码演示了如何将X类型的指针转化为Y类型的指针: +cgo存在的一个目的就是打破Go语言的禁止,恢复C语言应有的指针的自由转换和指针运算。以下代码演示了如何将X类型的指针转化为Y类型的指针: ```go var p *X @@ -402,9 +402,9 @@ p = (*X)(unsafe.Pointer(q)) // *Y => *X ## 2.3.7 切片间的转换 -在C语言中数组也一种指针,因此两个不同类型数组之间到转换和指针间转换基本类似。但是在Go语言中,数组或数组对应到切片都不再是指针类型,因为我们也就无法直接实现不同类型到切片之间的转换。 +在C语言中数组也一种指针,因此两个不同类型数组之间的转换和指针间转换基本类似。但是在Go语言中,数组或数组对应的切片都不再是指针类型,因此我们也就无法直接实现不同类型的切片之间的转换。 -不过Go语言的reflect包提供了切片类型到底层结构,再结合前面讨论到不同类型之间到指针转换技术就可以实现`[]X`和`[]Y`类型的切片转换: +不过Go语言的reflect包提供了切片类型的底层结构,再结合前面讨论到不同类型之间的指针转换技术就可以实现`[]X`和`[]Y`类型的切片转换: ```go var p []X @@ -418,7 +418,7 @@ pHdr.Len = qHdr.Len * unsafe.Sizeof(q[0]) / unsafe.Sizeof(p[0]) pHdr.Cap = qHdr.Cap * unsafe.Sizeof(q[0]) / unsafe.Sizeof(p[0]) ``` -不同切片类型之间转换到思路是先为构造一个空的目标切片,然后用原有的切片底层数据填充目标切片。如果X和Y类型的大小不同,需要重新设置Len和Cap属性。需要注意的是,如果X或Y是空类型,上述代码中可能导致除0错误,实际代码需要根据情况酌情处理。 +不同切片类型之间转换的思路是先构造一个空的目标切片,然后用原有的切片底层数据填充目标切片。如果X和Y类型的大小不同,需要重新设置Len和Cap属性。需要注意的是,如果X或Y是空类型,上述代码中可能导致除0错误,实际代码需要根据情况酌情处理。 下面演示了切片间的转换的具体流程: