参考
目录
1. 第一个程序
2. 格式化字符串
3. 变量的基本使用
4. 常量
5.运算符
6. 条件语句
7.循环语句
1 name
2 school
8. 函数
9. 作用域
10. 数组
11. 指针
12. 结构体
13. 切片
14. 范围
15. 集合Map
16. 递归函数
17. 类型转换
18. 接口,需要理解,有点意思
19. 并发
1. 第一个程序
package main
import "fmt"
func main(){
fmt.Println("hello world");
}
//go run test.go可以运行
//go build test.go 可以编译成exe文件
2. 格式化字符串
package main
import "fmt"
func main(){
var id = 123
var name = "tom"
var url = "id is %d, name is %s"
var newUrl = fmt.Sprintf(url, id, name)
fmt.Println(newUrl)
}
3. 变量的基本使用
package main
import "fmt"
// 这种因式分解关键字的写法一般用于声明全局变量,可以不使用(不报错)
var (
a int
b int
)
func main(){
var id int
id = 1
//g := 123只能在函数体内声明
g := 123 //推荐写法
var j = id
var aa string = "abc"
aa = "cd"
//空白标识符 _ 也被用于抛弃值
a1, _ := 2, 4
fmt.Print(id, g, j, &id, &j, " ", aa, " ", a1)
//输出: 1 123 1 0xc0000ac058 0xc0000ac070 cd 2
}
4. 常量
package main
import "fmt"
func main(){
const aa = "abc"
var alen = len(aa)
fmt.Print(alen)
//iota 用法
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
5.运算符
一些基本的操作
其他运算符
& 返回变量存储地址
* 指针变量
package main
import "fmt"
func main() {
var id = 4
var pst *int
pst = &id
fmt.Print(&id, pst)
//输出一样的地址
}
其实这样也输出一样的地址
package main
import "fmt"
func main() {
var id = 4
var pst = &id
fmt.Print(&id, pst)
//输出一样的地址
}
6. 条件语句
package main
import "fmt"
func main() {
var a = 111
if a < 20 {
fmt.Printf("a 小于 20\n" )
} else {
fmt.Printf("a 大于 20\n" )
}
var score = 60
switch score{
case 90:
fmt.Println("优秀");
case 80:
fmt.Println("良好");
case 60:
fmt.Println("及格");
}
var x interface{} = 7
switch x.(type){
case nil:
fmt.Print("x 的类型 nil")
case int:
fmt.Print("x 的类型int");
case float64:
fmt.Print("x 的类型float")
}
/*
fallthrough
使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。
*/
/*
select 语句。 select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
*/
}
7.循环语句
7.1 无限循环
func main() {
for true {
fmt.Printf("这是无限循环。\n");
}
}
7.2 for语句
7.2.1
func main() {
sum := 0
for i:=0; i<=10; i++{
sum += i
}
fmt.Println(sum)
}
7.2.2
func main() {
sum := 1
for ; sum <= 100;{
sum += sum
}
fmt.Println(sum)
}
7.2.3 可以简写7.2.2
func main() {
sum := 1
for sum <= 100{
sum += sum
}
fmt.Println(sum)
}
7.2.4 类似foreach
func main() {
arr := []string{"age", "name", "school"}
for k, v := range arr{
fmt.Println(k, v)
/*
输出
0 age
1 name
2 school
*/
}
}
7.3 break语句
7.3.1
func main() {
var a int = 10
for a<20 {
fmt.Printf("a的值是 %d\n", a)
a++;
if a>15 {
break;
}
}
}
7.3.2 不使用标记
func main() {
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break //跳出了当前循环
}
}
}
/*
输出:
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
*/
7.3.3 使用标记
func main() {
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break re//跳出到re
}
}
}
/*
输出:
i: 1
i2: 11
*/
7.4 continue
跳过当前循环执行下一次循环语句,也有标记和不标记
7.4.1 不使用标记
func main() {
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue
}
}
}
/*
输出:
i: 1
i2: 11
i2: 12
i2: 13
i: 2
i2: 11
i2: 12
i2: 13
i: 3
i2: 11
i2: 12
i2: 13
*/
7.4.2 使用标记
func main() {
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue re
}
}
}
/*
输出:
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
*/
7.4.3 和7.4.2效果一样
func main() {
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break
}
}
}
7.5 goto语句,在结构化程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱
8. 函数
8.1 值传递
这里x, y string 里的string要写,类型声明一样,不然会报undefined x undefined y
func swap(x, y string) (string, string){
return y, x
}
func main() {
a, b := swap("aa", "bb")
fmt.Println(a, b)
}
8.1.1 下面会报错
func swap(x, y string){
return "abc"
}
func main() {
a := swap("aa", "bb")
fmt.Println(a)
}
需要这样写才正确
func swap(x, y string) (string){
return "abc"
}
8.2 引用传递
func swap(x, y string){
tmp := x
x = y
y = tmp
}
func main() {
var a = "aa"
var b = "bb"
swap(a, b)
fmt.Println(a, b)
}
输出 aa bb
如果想被交换应该这样写
func swap(x *string, y *string){
tmp := *x
*x = *y
*y = tmp
}
func main() {
var a = "aa"
var b = "bb"
swap(&a, &b)
fmt.Println(a, b)
}
输出 bb aa
8.3 函数作为另外一个参数
// 声明一个函数类型
type cb func(int) int
func main() {
testCallBack(1, callBack)
testCallBack(2, func(x int) int {
fmt.Printf("我是回调,x:%d\n", x)
return x
})
}
func testCallBack(x int, f cb) {
f(x)
}
func callBack(x int) int {
fmt.Printf("我是回调,x:%d\n", x)
return x
}
输出:
我是回调,x:1
我是回调,x:2
8.4 闭包
和JavaScript的差不多
func getSequence() func() string {
i := "a"
return func() string {
i = i + "b"
return i
}
}
func main(){
/* nextNumber 为一个函数,函数 i 为 0 */
nextNumber := getSequence()
/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
}
输出
Ab
Abb
Abbb
8.5 函数 -(方法),比较特殊的用法
方法就是一个包含了接受者的函数
package main
import "fmt"
type Circle struct{
radius float64
}
func(cc Circle) getArea() float64{
return 3.14 * cc.radius * cc.radius
}
func main(){
var c1 Circle
c1.radius = 10.00
fmt.Print("圆的面积是", c1.getArea())
}
9. 作用域
在函数体外声明的变量称之为全局变量
10. 数组
func main(){
var balance [10] float32
var age = [5]float32{1,2,3,4}
fmt.Print(age, balance)
//少的补0,输出[1 2 3 4 0] [0 0 0 0 0 0 0 0 0 0]
var money = [5]float32{1:100, 3:400}
fmt.Print(money)
//输出[0 100 0 400 0],特殊指定索引的值
}
- 指针
略,上面有写到
- 结构体
12.1 定义结构体
func main(){
var b1 = Book{"laravel", "php框架", "xiaobai", 18}
fmt.Println(b1)
//age补0
var b2 = Book{name:"名字", title:"标题", author:"作者"}
fmt.Println(b2)
}
12.2 访问结构体成员
type Book struct{
title string
name string
author string
age int
}
func main(){
var b1 Book
b1.title = "Go 语言"
fmt.Printf("book title %s", b1.title)
fmt.Printf("book author %s", b1.author)
fmt.Printf("author age %d", b1.age)
/*
输出
book title Go 语言
book author
author age 0
*/
}
12.3 结构体作为函数参数
type Book struct{
title string
name string
author string
age int
}
func main(){
var b1 Book
b1.title = "Go 语言"
printInfo(b1)
}
func printInfo(bb Book){
fmt.Print(bb.title)
fmt.Print(bb.author)
}
12.4 结构体指针
type Book struct{
title string
name string
author string
age int
}
func main(){
var bb Book
bb.title = "标题"
bb.age = 18
printInfo(&bb)
}
func printInfo(myBook *Book){
fmt.Print(myBook.title)
fmt.Print(myBook.age)
}
12.5 和12.4效果一样
func main(){
var bb Book
bb.title = "标题"
bb.age = 18
printInfo(bb)
}
func printInfo(myBook Book){
fmt.Print(myBook.title)
fmt.Print(myBook.age)
}
- 切片
13.1 定义
可以声明一个未指定大小的数组来定义切片:
var bb []int
或者使用make来创建切片
func main(){
var bb []int = make([]int, 10)
fmt.Print(bb) //输出[0 0 0 0 0 0 0 0 0 0]
}
或者上面的简写为
func main(){
//var bb []int = make([]int, 10)
bb := make([]int, 10)
fmt.Print(bb) //输出[0 0 0 0 0 0 0 0 0 0]
}
13.2 切片初始化
func main(){
var arr = [] int {1,2,3,4,5,6}
fmt.Print(arr)//输出 [1 2 3 4 5 6]
s := arr[2:5] //startIndex 到 endIndex-1 下的元素创建为一个新的切片
fmt.Print(s)//输出[3 4 5]
s1 := arr[2:]
fmt.Print(s1)//输出 [3 4 5 6]
}
13.3 len()和cap() 函数
func main(){
var x = make([]int, 3, 5) //make([]T, length, capacity) capacity是容量大小
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x) //输出 len=3 cap=5 slice=[0 0 0]
}
13.4 空(nil)切片
func main() {
var numbers []int
if(numbers == nil){
fmt.Printf("切片是空的")
}
}
13.5 切片截取
Arr[from: to]
func main() {
/* 创建切片 */
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers) //cap is 9
numbers1 := make([]int,0,5)
printSlice(numbers1) //cap is 5
number2 := numbers[:2]
printSlice(number2) //cap is 9
number3 := numbers[1:5]
printSlice(number3) //cap is 8 左指针偏移了1步,所以cap为9-1=8
/*
输出
len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
len=4 cap=8 slice=[1 2 3 4]
*/
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
13.6 append()和copy() 函数
func main() {
var numbers []int
printSlice(numbers)
numbers = append(numbers, 0)
printSlice(numbers)
numbers = append(numbers, 1)
printSlice(numbers)
numbers = append(numbers, 2,3,4)
printSlice(numbers)//为什么这里容量是6
/*
解释如下
1.先将旧的slice容量乘以2,如果乘以2后的容量仍小于新的slice容量,则取新的slice容量(append多个elems)
2.如果新slice小于等于旧slice容量的2倍,则取旧slice容量乘以2
3.如果旧的slice容量大于1024,则新slice容量取旧slice容量乘以1.25
4.代码后面还会对newcap进行roundup,比如在64位平台,newcap是奇数的话就会+1
*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
copy(numbers1,numbers)
printSlice(numbers1)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
/*
输出
len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]
*/
- 范围
range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素
func main(){
sum := 0
var arr = []int{1,2,3,4}
for _,v := range arr{
sum += v
}
fmt.Print(sum)
}
- 集合Map
func main(){
var myMap map[string]string
myMap = make(map[string]string) //必须要加这个
myMap["name"] = "tom"
myMap["country"] = "China"
for k := range myMap{
fmt.Print(k, myMap[k])
}
vv, ok := myMap["name"] //这里name可以换成xxx
if(ok){
//输出: 某个exist-tom
fmt.Print("某个exist-", vv)
}else{
fmt.Print("不存在")
}
}
15.1 delete函数
func main(){
var myMap map[string]string
myMap = make(map[string]string) //必须要加这个
myMap["name"] = "tom"
myMap["country"] = "China"
delete(myMap, "name")
fmt.Print(myMap)
}
- 递归函数
略
- 类型转换
func main(){
var b = 123
var c float32
c = float32(b) // 不然c=b会报错
fmt.Print(c)
}
- 接口,需要理解,有点意思
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
18.1 例子1
package main
import (
"fmt"
)
type Phone interface {
call()
dd()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
func (nokiaPhone NokiaPhone) dd() {
fmt.Println("dd111")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone.dd()
}
18.2 例子2
package main
import (
"fmt"
)
type Sleeper interface{
Sleep()
}
type Dog struct{
Name string
}
func (d Dog) Sleep(){
fmt.Printf("Dog %s is sleeping\n", d.Name)
}
func AnimalSleep(s Sleeper){
s.Sleep()
}
//用go的接口实现了多态,我们先声明了一个接口类型的值(这里是var s Sleeper),只要实现了这个接口的struct变量(这里是Sleep()),都可以赋值给它,而调用方法的时候,go会根据实际类型选择使用哪个struct的方法。
func main(){
var s Sleeper
dog := Dog{Name: "xiaobai"}
//1 https://www.bilibili.com/video/BV1MC4y187bo?t=549
s = dog //假想:一个dog的实例,给一个接口的实例
AnimalSleep(s)
//2
sleepList := []Sleeper{Dog{Name: "wangwang"}}
for _, s := range sleepList{
s.Sleep()
}
}
18.3 例子3 接口嵌入
package main
import (
"fmt"
)
type Sleeper interface{
Sleep()
}
type Eater interface{
Eat(foodName string)
}
type LazyAnimal interface{
Sleeper
Eater
}
type Dog struct{
Name string
}
func (d Dog) Sleep(){
fmt.Printf("Dog %s is sleeping\n", d.Name)
}
func (d Dog) Eat(foodName string){
fmt.Printf("Dog %s is eating %s\n", d.Name, foodName)
}
func AnimalSleep(s Sleeper){
s.Sleep()
}
func main(){
var lz LazyAnimal
dog := Dog{Name: "xiaobai"}
lz = dog
lz.Sleep()
lz.Eat("chocolate")
/*
输出
Dog xiaobai is sleeping
Dog xiaobai is eating chocolate
*/
//类型断言
if dogBB,ok := lz.(Dog); ok{
fmt.Printf("I am a Dog, my name is %s", dogBB.Name)
}
}
- 并发
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。 goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
19.1 go并发
package main
import (
"fmt"
"time"
)
func say(s string){
for i:=0; i<5; i++{
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main(){
go say("world")
say("hello")
/*
输出
hello
world
world
hello
hello
world
world
hello
world
hello
或者又可能
world
hello
world
hello
hello
world
world
hello
hello
*/
}
19.2 通道 channel,计算就和
package main
import (
"fmt"
)
func sum(s []int, c chan int){
sum :=0
for _,v :=range s{
sum += v
}
c <- sum //把sum发送到c通道
}
func main(){
s := []int{7, 2, 8, -9, 4, 2}
c := make(chan int)
go sum(s[:len(s) / 2], c)
go sum(s[len(s) / 2:], c)
x, y := <-c, <-c //从通道c中接收值
fmt.Println(x, y , x+y) //输出:-3 17 14
}
19.3 通道缓冲区
通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小:
ch := make(chan int, 100)
19.4 遍历通道与关闭通道
略