Go语言22讲

01基本go程序

package main		//属于哪个包
import "fmt"		//导入包
func main() {
	fmt.Println("Hello, 世界")
}

环境变量设置

  • GOPATH:代表 Go 语言项目的工作目录
  • GOBIN:代表 Go 编译生成的程序的安装目录

02变量

var 变量名 类型 = 表达式

//声明一个变量
var i int = 10

//一次声明多个变量
var (
	j int = 0
    k int = 1
)

//自动推导
var (
	j = 0
    k = 1
)

//简短声明
i := 10
bf := false
str := "Hello"

基础类型

整形:

  • 有符号整型:如 int、int8、int16、int32 和 int64。
  • 无符号整型:如 uint、uint8、uint16、uint32 和 uint64。

浮点数:float32 和 float64

布尔型:true 和false

字符串:string

指针:pi := &i

常量:

const name = "Hello"
const (
	one = 1
    two = 2
    three = 3
    four = 4
)

//iota等价写法
const (
	one = iota + 1
    two
    three
    four
)

未初始化的值会设为零值

变量之间的转换

i2s := strconv.Itoa(i)
s2i,err := strconv.Atoi(i2s)
fmt.Println(i2s,s2i,err)

i2f:=float64(i)
f2i:=int(f64)
fmt.Println(i2f,f2i)

string包

//判断s1的前缀是否是H
fmt.Println(strings.HasPrefix(s1,"H"))
//在s1中查找字符串o
fmt.Println(strings.Index(s1,"o"))
//把s1全部转为大写
fmt.Println(strings.ToUpper(s1))

03控制结构

if

if i > 10 {
	
} else if {

} else {

}

if i := 6; i > 10 {

} else if {

} else {

}

switch

switch i := 6 {
case i > 10 :
	...
case i > 5 && i <= 10:
	...
default:
	...
}

switch j := 1; j {
case 1 :
	...
case 2 :
	...
default:
	...
}

switch 2>1 {
case true:
    fmt.Println("2>1")
case false:
    fmt.Println("2<=1")
}

for

sum := 0
for i := 1; i <= 100; i++ {
    sum+=i
}

sum := 0
i := 1
for i <= 100 {
    sum += i
    i++
}

sum := 0
i := 1
for {
    sum += i
    i++
    if i > 100 {
        break
    }
}

04集合

数组

array: = [5]string{"a","b","c","d","e"}

array := [...]string{"a","b","c","d","e"}

for i, v := range array{
    fmt.Printf("数组索引:%d,对应值:%s\n", i, v)
}

for _, v := range array{
    fmt.Printf("对应值:%s\n", v)
}

//二维数组
aa := [3][3]int{}

切片

slice:=array[start : end]

array:=[5]string{"a","b","c","d","e"}
slice:=array[2:5]

array[:4] 	//等价于 array[0:4]。
array[1:] 	//等价于 array[1:5]。
array[:] 	//等价于 array[0:5]。

//追加一个元素
slice2 := append(slice1,"f")
//多加多个元素
slice2 := append(slice1,"f","g")
//追加另一个切片
slice2 := append(slice1,slice...)

map

相当于unordered_map

nameAgeMap := make(map[string]int)

nameAgeMap["飞雪无情"] = 20
nameAgeMap := map[string]int{"飞雪无情":20}

//添加键值对或者更新对应 Key 的 Value
nameAgeMap["飞雪无情"] = 20
//获取指定 Key 对应的 Value
age:=nameAgeMap["飞雪无情"]

age,ok:=nameAgeMap["飞雪无情1"]
if ok {
    fmt.Println(age)
}
for k,v:=range nameAgeMap{
    fmt.Println("Key is",k,",Value is",v)
}

string和[]byte

//使用 [] 操作符获取指定索引的字节值
s := "Hello飞雪无情"
bs := []byte(s)

函数和方法

函数

**func funcName(params) result { body }

func sum(a, int, b, int) int {
	return a + b
}
res := sum(1 , 2)

函数的多值返回

第一个值返回函数的结果,第二个值返回函数出错的信息,这种就是多值返回的经典应用。

func sum(a, b int) (int, error) {
	if a < 0 || b < 0 {
    	return 0, error.New("a或者b不能是负数")
    }
    return a + b, nil
}

res, err := sum(1, 2)
if err != nil {
	fmt.Println(err)
} else {
	fmt.Println(res)
}
//不使用err
res, _ := sum(1, 2)

命名返回参数

func sum( a, b int) (sum int, err, error) {
	if a < 0 || b < 0 {
    	return 0, errors.New("a或者b不能是负数")
    }
    sum = a + b
    err = nil
    return
}

可变参数

可变参数的类型其实就是切片,如果你定义的函数中既有普通参数,又有可变参数,那么可变参数一定要放在参数列表的最后一个,比如 sum1(tip string,params …int).

func sum1(params ... int) int {
	sum := 0
    for _, i := range params {
    	sum += i
    }
    return sum
}

包级函数

函数名称的首字母要大写,比如 Println

  • 函数名称首字母小写代表私有函数,只有在同一个包中才可以被调用;
  • 函数名称首字母大写代表公有函数,不同的包也可以调用;
  • 任何一个函数都会从属于一个包。

匿名函数和闭包

有了匿名函数,就可以在函数中再定义函数(函数嵌套)

//sum2是函数类型的变量
sum2 := func(a, b int) int {
	return a + b;
}
fmt.Println(sum2(1, 2))

方法

Go 语言中,方法和函数是两个概念,但又非常相似,不同点在于方法必须要有一个接收者,这个接收者是一个类型,这样方法就和这个类型绑定在一起,称为这个类型的方法。

type Age uint 表示定义一个新类型 Age,该类型等价于 uint,可以理解为类型 uint 的重命名(C++ 中的typedef)。示例中方法 String() 就是类型 Age 的方法,类型 Age 是方法 String() 的接收者。

和函数不同,定义方法时会在关键字 func 和方法名 String 之间加一个接收者 (age Age) ,接收者使用小括号包围。

type Age uint
func (age Age) String() {
    fmt.Println("the age is", age)
}

age := Age(25)
age.String()

在调用方法的时候,传递的接收者本质上都是副本,只不过一个是这个值副本,一是指向这个值指针的副本。

06struct和interface

type person struct {
	name string
    age uint
}
var p1 person
p2 := person{"飞雪无情", 30}
p3 := person{age:30, name:"飞雪无情"}
p4 := person{age:30}
fmt.Println(p2.name, p.age)

结构体嵌套

type person struct {
	name string
    age uint
    addr address
}
type addr struct {
	province string
    city sstring
}

p := person {
	age : 30,
    name : "飞雪无情"
    addr : addr {
    	province : "北京"
        city : "北京"
    }
}
fmt.Println(p.addr.city)

接口

接口是和调用方的一种约定,它是一个高度抽象的类型,不用和具体的实现细节绑定在一起。接口要做的是定义好约定,告诉调用方自己可以做什么,但不用知道它的内部实现,这和我们见到的具体的类型如 int、map、slice 等不一样。

接口的定义和结构体稍微有些差别,虽然都以 type 关键字开始,但接口的关键字是 interface,表示自定义的类型是一个接口。也就是说 Stringer 是一个接口,它有一个方法 String() string,整体如下面的代码所示:

package main

import "fmt"

type Sleeper interface {
	Sleep() //声明一个Sleep()方法
}

type Dog struct {
	Name string
}
type Cat struct {
	Name string
}

func (d Dog) Sleep() {
	fmt.Printf("Dog %s is sleeping\n", d.Name)
}

func (c Cat) Sleep() {
	fmt.Printf("Cat %s is sleeping\n", c.Name)
}

func AnimalSleep(s Sleeper) {
	s.Sleep()
}

func main() {
	var s Sleeper
	dog := Dog{"xiaohei"}
	cat := Cat{"kitty"}
	s = dog
	AnimalSleep(s)
	s = cat
	AnimalSleep(s)
    
    sleepList := []Sleeper{Dog{"xiaobai"}, Cat{"xiaohei"}}
	for _, s := range sleepList {
		s.Sleep()
	}
}

工厂函数

工厂函数一般用于创建自定义的结构体,便于使用者调用

func NewPerson(name string) * person {
	return &person{name: name}
}

p1:=NewPerson("张三")			//创建一个*person 类型的变量 p1

我定义了一个工厂函数 NewPerson,它接收一个 string 类型的参数,用于表示这个人的名字,同时返回一个*person。

通过工厂函数创建自定义结构体的方式,可以让调用者不用太关注结构体内部的字段,只需要给工厂函数传参就可以了。

全部评论

相关推荐

昨天 09:08
裁应届生,一分钱补偿没有,离职了还脑控你,跟踪你,定位你,丁东服务是搞系每一个人
牛客吹哨人:建议细说...哨哥晚点统一更新到黑名单:不要重蹈覆辙!25届毁意向毁约裁员黑名单https://www.nowcoder.com/discuss/1317104
叮咚买菜稳定性 10人发布 投递叮咚买菜等公司10个岗位 >
点赞 评论 收藏
分享
10-09 22:05
666 C++
找到工作就狠狠玩CSGO:报联合国演讲,报电子烟设计与制造
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务