Go 笔记

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
_,numb,strs := numbers() //只获取函数返回值的后两个
fmt.Println(numb,strs)
}

//一个可以返回多个值的函数
func numbers()(int,int,string){
a , b , c := 1 , 2 , "str"
return a,b,c
}

函数

1
2
3
4
5
6
7
8
9
10
11
12
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int

if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}

作用域

go的作用域只有两个,局部与全局
全局作用域:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

/* 声明全局变量 */
var g int

func main() {

/* 声明局部变量 */
var a, b int

/* 初始化参数 */
a = 10
b = 20
g = a + b

fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g)
}

全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑
形式参数会作为函数的局部变量来使用
可通过花括号来控制变量的作用域,花括号中的变量是单独的作用域,同名变量会覆盖外层

1
2
3
4
5
6
7
8
9
10
a := 5
{
a := 3
fmt.Println("in a = ", a)
}
fmt.Println("out a = ", a)

输出:
in a = 5
out a = 5

数组

初始化

1
2
3
4
5
6
7
8
9
10
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

// 将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}

读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func main() {
var n [10]int /* n 是一个长度为 10 的数组 */
var i,j int

/* 为数组 n 初始化元素 */
for i = 0; i < 10; i++ {
n[i] = i + 100 /* 设置元素为 i + 100 */
}

/* 输出每个数组元素的值 */
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j] )
}
}

指针

取地址符: &
取一个数字的地址:

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
var a int = 10

fmt.Printf("变量的地址: %x\n", &a )
}

一个指针变量指向了一个值的内存地址
声明:

1
2
var ip *int        /* 指向整型*/
var fp *float32 /* 指向浮点型 */

指针用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func main() {
var a int= 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */

ip = &a /* 指针变量的存储地址 */

fmt.Printf("a 变量的地址是: %x\n", &a )

/* 指针变量的存储地址 */
fmt.Printf("ip 变量储存的指针地址: %x\n", ip )

/* 使用指针访问值 */
fmt.Printf("*ip 变量的值: %d\n", *ip )
}

输出结果:
a 变量的地址是: 20818a220
ip 变量储存的指针地址: 20818a220
*ip 变量的值: 20

空指针:当一个指针被定义后没有分配到任何变量时,它的值为 nil

空指针判断

1
2
if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil) /* ptr 是空指针 */

打印指针的时候,直接输出ptr为他保存的地址,输出*ptr,输出的是他地址保存的值

至于指针数组,习惯于写java的同学则不建议使用这种,容易造成混乱
指针这种东西,看得懂别人的代码就可以了,自己使用平时简单的使用*p这种形式就足够了

结构体

类似java的类,如果在一个go文件内写,类似java的内部类(innerClass)
结构体定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

type Books struct {
title string
author string
subject string
book_id int
}


func main() {

// 创建一个新的结构体
fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})

// 也可以使用 key => value 格式
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})

// 忽略的字段为 0 或 空
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})

//类似java中使用属性的方式
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
}

输出结果:
{Go 语言 www.runoob.com Go 语言教程 6495407}
{Go 语言 www.runoob.com Go 语言教程 6495407}
{Go 语言 www.runoob.com 0}

结构体指针在使用中经常见到,建议多看例子

Tips:
如果想在函数里面改变结果体数据内容,需要传入指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407

printBook(&Book1) //此处如下传值,这种形式非常常见

func printBook( book *Books ) {
fmt.Printf( "Book title : %s\n", book.title)
fmt.Printf( "Book author : %s\n", book.author)
fmt.Printf( "Book subject : %s\n", book.subject)
fmt.Printf( "Book book_id : %d\n", book.book_id)
}
```
**敲黑板,划重点**
>结构体中属性的首字母大小写问题
首字母大写相当于 public
首字母小写相当于 private
这个 public 和 private 是相对于包(go 文件首行的 package 后面跟的包名)来说的

**当要将结构体对象转换为 JSON 时,对象中的属性首字母必须是大写,才能正常转换为 JSON**

```go
type Person struct {
   Name string      //Name字段首字母大写
   age int //age字段首字母小写
}

func main() {
  person:=Person{"小明",18}
  if result,err:=json.Marshal(&person);err==nil{ //json.Marshal 将对象转换为json字符串
    fmt.Println(string(result))
  }
}
```
>输出
{"Name":"小明"} //只有Name,没有age


JSON一般建议这么写
```go
type Person struct{
  Name string `json:"name"`  //标记json名字为name   
  Age int `json:"age"`
  Time int64 `json:"-"` // 标记忽略该字段

}

func main(){
  person:=Person{"小明",18, time.Now().Unix()}
  if result,err:=json.Marshal(&person);err==nil{
   fmt.Println(string(result))
  }
}
```

如果你想编写智能合约,上述的结构体是必不可少的

# 切片Slice
应该是动态扩容数组,Java中叫List
```go
var slice1 []type = make([]type, len)

//也可以简写为
slice1 := make([]type, len)

//也可以指定容量
make([]T, length, capacity)

感觉这个不老好用的

数据类型转换

String 转int

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main
import (
"fmt"
"strconv"
)

func main() {
// string to int
aStr := "100"
bInt, err := strconv.Atoi(aStr)

if err == nil {
fmt.Printf("aStr:%T %s,bInt:%T %d", aStr, aStr, bInt, bInt)
} else {
fmt.Printf("err:%s", err)
}

// int to string
cInt := 200
dStr := strconv.Itoa(cInt)

fmt.Printf("cInt:%T %d,dStr:%T %s", cInt, cInt, dStr, dStr)
}

接口

学接口的时候,先理解下面这段话

如果您曾经是面向对象的程序员,您肯定会经常使用implements关键字来实现接口。 但是在go中,你没有明确提到一个类型是否实现了一个接口。 如果一个类型实现了在接口中定义的签名方法,则称该类型实现该接口。 就像说它像鸭子一样走路,像鸭子一样游泳,像鸭子一样嘎嘎叫,那就是鸭子。

不存在继承这个东西
接口的声明更像是一个注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"fmt"
)

type Phone interface {
call()
}

type NokiaPhone struct {
}

func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
}

func (iPhone IPhone) call() {
fmt.Println("I am iPhone, I can call you!")
}

func main() {
var phone Phone

phone = new(NokiaPhone)
phone.call()

phone = new(IPhone)
phone.call()

}

看不懂吗?没关系,我也不太懂

1
2
3
4
5
6
7
func (name string) imp() string{
print("这是实现方法的写法")
}

func sum(x int,y int) int{
print("这是正常写法")
}

请我喝杯咖啡吧~

支付宝
微信