7

Go语言类型断言、类型选择、指针、数组的问题以及生成二进制可执行文件去部署项目

 3 years ago
source link: http://www.lzhpo.com/article/144
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Go语言类型断言、类型选择、指针、数组的问题以及生成二进制可执行文件去部署项目

类型断言 提供了访问接口值底层具体值的方式。

t := i.(T)

该语句断言接口值 i 保存了具体类型 T,并将其底层类型为 T 的值赋予变量 t

i 并未保存 T 类型的值,该语句就会触发一个panic错误。

为了 判断 一个接口值是否保存了一个特定的类型,类型断言可返回两个值:其底层值以及一个报告断言是否成功的布尔值。

t, ok := i.(T)

i 保存了一个 T,那么 t 将会是其底层值,而 oktrue

否则,ok 将为 falset 将为 T 类型的零值,程序并不会产生panic

package mainimport "fmt"func main() {    var i interface{} = "hello"    s := i.(string)    fmt.Println(s)    s, ok := i.(string)    fmt.Println(s, ok)    f, ok := i.(float64)    fmt.Println(f, ok)    f = i.(float64) // 报错(panic)    fmt.Println(f)}

运行结果:

hellohello true0 falsepanic: interface conversion: interface {} is string, not float64goroutine 1 [running]:main.main()    /tmp/sandbox028318339/prog.go:17 +0x1f4

类型选择 是一种按顺序从几个类型断言中选择分支的结构。

类型选择与一般的 switch 语句相似,不过类型选择中的 case 为类型(而非值), 它们针对给定接口值所存储的值的类型进行比较。

switch v := i.(type) {case T:    // v 的类型为 Tcase S:    // v 的类型为 Sdefault:    // 没有匹配,v 与 i 的类型相同}

类型选择中的声明与类型断言 i.(T) 的语法相同,只是具体类型 T 被替换成了关键字 type

此选择语句判断接口值 i 保存的值类型是 T 还是 S。在 TS 的情况下,变量 v 会分别按 TS 类型保存 i 拥有的值。在默认(即没有匹配)的情况下,变量 vi 的接口类型和值相同。

package mainimport "fmt"func do(i interface{}) {    switch v := i.(type) {    case int:        fmt.Printf("Twice %v is %v\n", v, v*2)    case string:        fmt.Printf("%q is %v bytes long\n", v, len(v))    default:        fmt.Printf("I don't know about type %T!\n", v)    }}func main() {    do(21)    do("hello")    do(true)}

运行结果:

Twice 21 is 42"hello" is 5 bytes longI don't know about type bool!Program exited.

Stringer

fmt 包中定义的 Stringer 是最普遍的接口之一。

type Stringer interface {    String() string}

Stringer 是一个可以用字符串描述自己的类型。fmt 包(还有很多包)都通过此接口来打印值。

# 官网api介绍type Stringertype Stringer interface {    String() string}Stringer 接口由任何拥有 String 方法的值所实现,该方法定义了该值的“原生”格式。 String 方法用于打印值,该值可作为操作数传至任何接受字符串的格式,或像 Print 这样的未格式化打印器。
package mainimport "fmt"type Person struct {    Name string    Age  int}func (p Person) String() string {    return fmt.Sprintf("%v (%v years)", p.Name, p.Age)}func main() {    a := Person{"Arthur Dent", 42}    z := Person{"Zaphod Beeblebrox", 9001}    fmt.Println(a, z)}

运行结果:

Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)Program exited.

Reader

io 包指定了 io.Reader 接口,它表示从数据流的末尾进行读取。

Go 标准库包含了该接口的许多实现,包括文件、网络连接、压缩和加密等等。

io.Reader 接口有一个 Read 方法:

func (T) Read(b []byte) (n int, err error)

Read 用数据填充给定的字节切片并返回填充的字节数和错误值。在遇到数据流的结尾时,它会返回一个 io.EOF 错误。

示例代码创建了一个 strings.Reader 并以每次 8 字节的速度读取它的输出。

package mainimport (    "fmt"    "io"    "strings")func main() {    r := strings.NewReader("Hello, Reader!")    b := make([]byte, 8)    for {        n, err := r.Read(b)        fmt.Printf("n = %v err = %v b = %v\n", n, err, b)        fmt.Printf("b[:n] = %q\n", b[:n])        if err == io.EOF {            break        }    }}

运行结果:

n = 8 err = <nil> b = [72 101 108 108 111 44 32 82]b[:n] = "Hello, R"n = 6 err = <nil> b = [101 97 100 101 114 33 32 82]b[:n] = "eader!"n = 0 err = EOF b = [101 97 100 101 114 33 32 82]b[:n] = ""

Go语言指针符号的*和&

&符号的意思是对变量取地址,如:变量a的地址是&a

*符号的意思是对指针取值,如:*&a,就是a变量所在地址的值,当然也就是a的值了

生成二进制可执行文件去部署项目

set GOARCH=amd64set GOOS=linuxgo build -o ds-customers main.go

之后上传到Linux上:

chmod +x ds-customers
./ds-customers

Go语言数组的问题

直接上代码

var group []stringgroup[0]="abc"fmt.Println(group[0])123

编译正常,运行报错如下

panic: runtime error: index out of rangegoroutine 1 [running]:panic(0x47a880, 0xc42000a110)    /opt/tools/go1.7.3/src/runtime/panic.go:500 +0x1a1main.main()    /opt/IdeaProjects/test-embeded-struct/main.go:11 +0x14exit status 212345678

index越界,于是改了一下代码

var group []stringfmt.Println(len(group))fmt.Println(cap(group))group[0]="abc"fmt.Println(group[0])12345
00panic: runtime error: index out of rangegoroutine 1 [running]:panic(0x48fec0, 0xc42000a110)    /opt/tools/go1.7.3/src/runtime/panic.go:500 +0x1a1main.main()    /opt/IdeaProjects/test-embeded-struct/main.go:13 +0x10aexit status 212345678910

也就是说,slice声明的时候如果不同时初始化数据,默认长度和容量都是0,下标0意味着长度是1,所以index越界了。


那么,使用slice的时候有下面几种方式


第一,声明的时候初始化数据,例如

test:=[]string{"a","b","c"}1

第二,从已经初始化数据的slice‘切’出来

test:=[]string{"a","b","c"}your_string=test[0:1]12

第三,append方法,会默认扩容,

var group []stringfmt.Println(len(group))fmt.Println(cap(group))group=append(group,"hahaha")group[0]="abc"fmt.Println(len(group))fmt.Println(cap(group))fmt.Println(group[0])12345678
0011abc12345

append方法在slice长度不足的时候,会进行扩容,注释如下

// The append built-in function appends elements to the end of a slice. If// it has sufficient capacity, the destination is resliced to accommodate the// new elements. If it does not, a new underlying array will be allocated.// Append returns the updated slice. It is therefore necessary to store the// result of append, often in the variable holding the slice itself://  slice = append(slice, elem1, elem2)//  slice = append(slice, anotherSlice...)// As a special case, it is legal to append a string to a byte slice, like this://  slice = append([]byte("hello "), "world"...)func append(slice []Type, elems ...Type) []Type
正文到此结束
所属分类:Go开发

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK