go的语法基础
hello world
package main
import "fmt"
func main() {
fmt.Println("hello world")
// 简易版
println("hello world")
}
/**
go run [path] 直接运行程序
go build [path] 将程序编译成二进制,会变成一个exe文件,通过.[path]执行该程序
*/
1.Go语言使用包来组织源代码的,并实现命名空间的管理,任何一个Go语言程序必须属于一个包,即每个go程序的开头要写上package <pkg_name>。
2.fmt--是一个控制输出的包
类型
package main
func main() {
// 变量声明的方式,以整型为例子
var intNum1 int = 0
var intNum2, intNum3 int = 1, 2
var intNum4 = 3
// 简易声明,类型自动推断
intNum5 := 5
println(intNum1)
println(intNum2, intNum3)
println(intNum4)
println(intNum5)
//go中一次声明多个变量
var (
a string
b int
c bool
d float32
)
//go多个变量声明并且赋值
var name,sex = "gogo", 1
// 常量
const PI float32 = 3.1415926
println(PI)
// 布尔
flag := false
println(flag)
// 浮点型64
var float64Num float64
println(float64Num)
// 浮点型32
float32Num := float32(float64Num)
println(float32Num)
// 字符串
str := "你好"
str += "世界"
println(str)
//一个常量计数器-- iota
}
/**
Go是一门强类型的语言
变量声明可以省略类型,但不能省略var关键字,类型省略可以根据变量的值自动推导
*/
if-else
package main
func main() {
// if - else
if 7%2 == 0 {
// 偶数
println("7 is even")
} else {
// 奇数
println("7 is odd")
}
// if - else if - else
// num给其一个初始条件
if num := 9; num < 0 { // 如果 num < 0--这里可以直接赋值
println(num, "is negative") // 输出它是一个负数
} else if num == 0 {
println(num, "is zero") // 输出它是一个0
} else {
println(num, "is positive") // 输出它是一个正数
}
}
循环
//go没有while,do while, 只能使用for
package main
func main() {
//这个就等同于while(true)
for {
println(1)
break
}
// 打印0-9
for i := 0; i < 10; i++ {
println(i)
}
}
switch
package main
import "time"
func main() {
a := 2
switch a {
case 1:
println("one")
case 2:
println("two")
default:
println("不知道")
}
t := time.Now()//获取当前时间
println(t)
// 特殊用法,可以取代if - else
switch {
case t.Hour() < 12:
println("早于中午")
default:
println("晚于中午")
}
}
/**
switch自带一个break,这是和其他语言不同之处
*/
数组
package main
import (
"fmt"
)
var arr0 [5]int = [5]int{1, 2, 3}
var arr1 = [5]int{1, 2, 3, 4, 5}
var arr2 = [...]int{1, 2, 3, 4, 5, 6}
var str = [5]string{3: "hello world", 4: "tom"}
func main() {
a := [3]int{1, 2} // 未初始化元素值为 0。
b := [...]int{1, 2, 3, 4} // 通过初始化值确定数组长度。
c := [5]int{2: 100, 4: 200} // 使用引号初始化元素。--蛮特别的
d := [...]struct {
name string
age uint8
}{
{"user1", 10}, // 可省略元素类型。
{"user2", 20}, // 别忘了最后一行的逗号。
}
fmt.Println(arr0, arr1, arr2, str)
fmt.Println(a, b, c, d)
}
/*
[1 2 3 0 0] [1 2 3 4 5] [1 2 3 4 5 6] [ hello world tom]
[1 2 0] [1 2 3 4] [0 0 100 0 200] [{user1 10} {user2 20}]
**/
//多维数组
package main
import (
"fmt"
)
var arr0 [5][3]int
var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
func main() {
a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
b := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // 第 2 纬度不能用 "..."。
fmt.Println(arr0, arr1)
fmt.Println(a, b)
}
/*
[[0 0 0] [0 0 0] [0 0 0] [0 0 0] [0 0 0]] [[1 2 3] [7 8 9]]
[[1 2 3] [4 5 6]] [[1 1] [2 2] [3 3]]
*/
slice切片
package main
import "fmt"
func main() {
// 用make创建切片,需要指定初始长度
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
// 新增,需要用一个切片变量接收,容量不够会扩容,返回一个新的slice
s = append(s, "d")
sNew := append(s, "e", "f")
fmt.Println(sNew)
// copy
a := make([]string, len(sNew))
copy(a, sNew)
fmt.Println(a)
// 切片操作
fmt.Println(a[:]) // 所有
fmt.Println(a[2:5]) // 区间[2,5)
fmt.Println(s[:3]) // [0,3)
fmt.Println(s[1:]) // 1到结尾
// 简易定义
good := []string{"g", "o", "o", "d"}
fmt.Println(good)
good = append(good, "!")
fmt.Println(good)
// 区别数组: b := [5]int{1, 2, 3, 4, 5},是需要指定长度的
}
/**
切片是一个可变长数组,不用指定其长度。[]类型
和python很是相似,但这个没有负数的索引
*/
map
package main
import "fmt"
func main() {
// key string, value int
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m)
fmt.Println(len(m)) //2
fmt.Println(m["one"]) //1
fmt.Println(m["two"]) //2
fmt.Println(m["three"]) //0
// ok 获取map中是否有这个key存在
r, ok := m["three"]
//fmt.Println(r)
//fmt.Println(ok)
fmt.Println(r, ok)
// 删除key为one
delete(m, "one")
// 简易定义
m2 := map[string]int{"one": 1, "two": 2}
fmt.Println(m2)
// 遍历map,同理可以遍历数组--遍历很特别
for key, value := range m {
println(key, value) // key,value
}
}
/**
map 是无序的,Map呢这个和c++中stl库中保持高度一致,理解不差
但是可以发现这边的map方法明显少,但是同时使用多个变量去获取倒是多,可能是语言特色
*/
函数
函数声明包含一个函数名,参数列表, 返回值列表和函数体。如果函数没有返回值,则返回列表可以省略。函数从第一条语句开始执行,直到执行return语句或者执行函数的最后一条语句。
函数可以没有参数或接受多个参数。
注意类型在变量名之后 。
当两个或多个连续的函数命名参数是同一类型,则除了最后一个类型之外,其他都可以省略。
函数可以返回任意数量的返回值。
使用关键字 func 定义函数,左大括号依旧不能另起一行。
func test(x, y int, s string) (int, string) {
// 类型相同的相邻参数,参数类型可合并。 多返回值必须用括号。
n := x + y
return n, fmt.Sprintf(s, n)
}
//函数是第一类对象,可作为参数传递。建议将复杂签名定义为函数类型,以便于阅读。
import "fmt"
func test(fn func() int) int {
return fn()
}
// 定义函数类型。
type FormatFunc func(s string, x, y int) string
func format(fn FormatFunc, s string, x, y int) string {
return fn(s, x, y)
}
func main() {
s1 := test(func() int { return 100 }) // 直接将匿名函数当参数。
s2 := format(func(s string, x, y int) string {
return fmt.Sprintf(s, x, y)
}, "%d, %d", 10, 20)
println(s1, s2)
}
// 100 10, 20
结构体
也和c++差不多
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
type person struct {
name string
city string
age int8
}
func main() {
var p1 person
p1.name = "pprof.cn"
p1.city = "北京"
p1.age = 18
fmt.Printf("p1=%v\n", p1) //p1={pprof.cn 北京 18}
fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"pprof.cn", city:"北京", age:18}
}
指针
这个c++指针类似,*和&符号使用
new和make:
1.二者都是用来做内存分配的。 2.make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身; 3.而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。
func main() {
var a int
fmt.Println(&a)//输出a的地址
var p *int
p = &a //将指针p指向a这样a和p指向的就是同一块内存地址
*p = 20
fmt.Println(a)
}