forked from hantmac/Mastering_Go_ZH_CN
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request hantmac#137 from luobangkui/2.3.3-2.3.5
完成2.3.3-2.3.5章节
- Loading branch information
Showing
4 changed files
with
138 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
### Unsafe code | ||
|
||
**Unsafe code**是一种绕过go类型安全和内存安全检查的Go代码。大多数情况,unsafe code是和指针相关的。但是要记住使用unsafe code有可能会损害你的程序,所以,如果你不完全确定是否需要用到unsafe code就不要使用它。 | ||
|
||
以下面的```unsafe.go```为例,看一下unsafe code的使用 | ||
|
||
``` | ||
package main | ||
import ( | ||
"fmt" | ||
"unsafe" | ||
) | ||
func main() { | ||
var value int64 = 5 | ||
var p1 = &value | ||
var p2 = (*int32)(unsafe.Pointer(p1)) | ||
``` | ||
这里使用了```unsafe.Pointer()```方法,这个方法能让你创造一个```int32```的```p2```指针去指向一个```int64```的```value```变量,而这个变量是使用```p1```指针去访问的,注意这种做法是有风险的。 | ||
|
||
任何go指针都可以转化为```unsafe.Pointer```指针。 | ||
|
||
###### *```unsafe.Pointer```类型的指针可以覆盖掉go的系统类型。这毫无疑问很快,但是如果不小心或者不正确使用的话就会很危险,它给了开发者更多选择去掌控数据。* | ||
|
||
```unsafe.go```后面部分如下 | ||
|
||
``` | ||
fmt.Println("*p1: ", *p1) | ||
fmt.Println("*p2: ", *p2) | ||
*p1 = 5434123412312431212 | ||
fmt.Println(value) | ||
fmt.Println("*p2: ", *p2) | ||
*p1 = 54341234 | ||
fmt.Println(value) | ||
fmt.Println("*p2: ", *p2) | ||
} | ||
``` | ||
###### *你可以使用一个星号(***)来解引用一个指针* | ||
|
||
运行```unsafe.go```,会得到如下的输出 | ||
|
||
``` | ||
*p1: 5 | ||
*p2: 5 | ||
5434123412312431212 | ||
*p2: -930866580 | ||
54341234 | ||
*p2: 54341234 | ||
``` | ||
|
||
那么这个输出说明了什么呢?它告诉了我们,使用32-bit的指针无法存一个64-bit的整数型 | ||
|
||
下一节你会看到,使用```unsafe```库中的方法可以做许多有趣的事情 | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
### 关于unsafe包 | ||
|
||
你已经实际操作过```unsafe```包的东西了,现在来看一下为什么这个库这么特别。 | ||
|
||
|
||
|
||
首先,如果你看了```unsafe```包的源码,你可能会感到惊讶。在macOS Hight Sierra系统上,可以使用**Homebrew**安装1.9.1版本的Go 。```unsafe```源码路径在```/usr/local/Cellar/go/1.9.1/libexec/src/unsafe/unsafe.go```下面,不包含注释,它的内容如下 | ||
|
||
``` | ||
$ cd /usr/local/Cellar/go/1.9.1/libexec/src/unsafe/ | ||
$ grep -v '^//' unsafe.go|grep -v '^$' | ||
package unsafe | ||
type ArbitraryType int | ||
type Pointer *ArbitraryType | ||
func Sizeof(x ArbitraryType) uintptr | ||
func Offsetof(x ArbitraryType) uintptr | ||
func Alignof(x ArbitraryType) uintptr | ||
``` | ||
|
||
OK,其它的```unsafe```包的go代码去哪里了?答案很简单:当你import到你程序里的时候,Go编译器实现了这个unsafe库。 | ||
|
||
###### *许多系统库,例如```runtime```,```syscall```和```os```会经常使用到```usafe```库* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
### 另一个usafe包的例子 | ||
|
||
在这一节,你会了解到更多关于```unsafe```库的东西,以及通过一个```moreUnsafe.go```的小程序来了解unsafe库的兼容性。```moreUnsafe.go```做的事情就是使用指针来访问数组里的所有元素。 | ||
|
||
|
||
``` | ||
package main | ||
import ( | ||
"fmt" | ||
"unsafe" | ||
) | ||
func main() { | ||
array := [...]int{0, 1, -2, 3, 4} | ||
pointer := &array[0] | ||
fmt.Print(*pointer, " ") | ||
memoryAddress := uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0]) | ||
for i := 0; i < len(array)-1; i++ { | ||
pointer = (*int)(unsafe.Pointer(memoryAddress)) | ||
fmt.Print(*pointer, " ") | ||
memoryAddress = uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0]) | ||
} | ||
``` | ||
|
||
首先,```pointer```变量指向```array[0]```的地址,```array[0]```是整型数组的第一个元素。接下来指向整数值的```pointer```变量会传入```unsafe.Pointer()```方法,然后传入```uintptr```。最后结果存到了```memoryAddress```里。 | ||
|
||
|
||
```unsafe.Sizeof(array[0])```是为了去访问下一个数组元素,这个值是每个元素占的内存大小。每次for循环遍历,都会把这个值加到```memoryAddress```上,这样就能获取到下一个数组元素的地址。```*pointer```的*符号对指针进行解引用,然后返回了所存的整数值。 | ||
|
||
|
||
后面部分代码如下: | ||
|
||
|
||
``` | ||
fmt.Println() | ||
pointer = (*int)(unsafe.Pointer(memoryAddress)) | ||
fmt.Print("One more: ", *pointer, " ") | ||
memoryAddress = uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0]) | ||
fmt.Println() | ||
} | ||
``` | ||
|
||
这里,我们尝试使用指针和内存地址去访问一个不存在的数组元素。由于使用```unsafe```包,Go编译器不会捕捉到这样的逻辑错误,因而会产生一些不可预料的事情。 | ||
|
||
执行```moreUnsafe.go```,会产生如下的输出: | ||
|
||
``` | ||
$ go run moreUnsafe.go | ||
0 1 -2 3 4 | ||
One more: 824634191624 | ||
``` | ||
现在,你使用指针访问了Go数组里的所有元素。但是,这里真正的问题是,当你尝试访问无效的数组元素,程序并不会出错而是会返回一个随机的数字。 |