hello Go!
Go 语言的基础组成有以下几个部分:
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
在命令行使用go run helloworld.go运行
变量
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"
fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
fmt.Println(g) // initialapple
//const表示声明为常量
const s string = "constant"
const h = 500000000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
go语言可以不显示声明变量类型,可以通过var自动的进行类型声明var a int为主要的变量声明方式,表示声明一个int类型的变量,此外,可以通过a := 2声明一个int类型,值为2的变量a。
循环
go语言主要使用for循环,go的for循环不需要加括号。和java ,c类似,第一个条件为初始化,第二个为判断语句,第三个为循环结束后运行的语句。
i := 1
for {
fmt.Println("loop")
break
}
for j := 7; j < 9; j++ {
fmt.Println(j)
}
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i = i + 1
}
if判断
大体和其他语言类似,但是go语言中if可以和for一样,可以初始化变量
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
if 8%4 == 0 {
fmt.Println("8 is divisible by 4")
}
//这里初始化num为9
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
switch语句
go的switch语句不仅仅可以接受int char,即使是布尔类型,结构体也可以作为传参
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
//这里替代if语句
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
数组
//一维数组
var a [5]int
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
//初始化一维数组
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
//二维数组
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
slice切片
go里的slice切片类似java中的集合List
// 创建一个长度为3的字符串切片
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
// 向切片中添加一个元素
s = append(s, "d")
// 向切片中添加两个元素
s = append(s, "e", "f")
// 打印切片的所有元素
fmt.Println(s) // [a b c d e f]
// 创建一个新的切片c,其长度与s相同
c := make([]string, len(s))
// 将切片s的内容复制到切片c中
copy(c, s)
// 打印切片c的所有元素
fmt.Println(c) // [a b c d e f]
// 打印切片s从第三个元素到第五个元素的所有元素
fmt.Println(s[2:5]) // [c d e]
// 打印切片s从第一个元素到第五个元素的所有元素
fmt.Println(s[:5]) // [a b c d e]
// 打印切片s从第三个元素到最后一个元素的所有元素
fmt.Println(s[2:]) // [c d e f]
// 创建一个新的字符串切片good,并初始化它
good := []string{"g", "o", "o", "d"}
// 打印切片good的所有元素
fmt.Println(good) // [g o o d]
map
go中的map类似java的hashmap,存储k-v的结构
// 创建一个空的map,键为字符串string类型,值为整数int类型
m := make(map[string]int)
// 向map中添加一个键值对
m["one"] = 1
// 向map中添加一个键值对
m["two"] = 2
// 打印map
fmt.Println(m) // map[one:1 two:2]
// 打印map的长度
fmt.Println(len(m)) // 2
// 打印map中键为"one"的值
fmt.Println(m["one"]) // 1
// 打印map中键为"unknow"的值,因为该键不存在,所以返回默认值0
fmt.Println(m["unknow"]) // 0
// 使用ok-idiom检查map中键为"unknow"的值是否存在
r, ok := m["unknow"]
// 打印返回值和是否存在的标志
fmt.Println(r, ok) // 0 false
// 删除map中键为"one"的键值对
delete(m, "one")
// 创建一个新的map,并初始化它
m2 := map[string]int{"one": 1, "two": 2}
// 使用var关键字声明一个新的map,并初始化它
var m3 = map[string]int{"one": 1, "two": 2}
// 打印两个新map
fmt.Println(m2, m3)
map和slice都需要用到make关键字
range方法
有关切片的range方法
nums := []int{2, 3, 4}
sum := 0
//i为序号,num为slice元素
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
fmt.Println(sum) // 9
有关map的range方法
m := map[string]string{"a": "A", "b": "B"}
//k为key,v为value元素
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
for k := range m {
fmt.Println("key", k) // key a; key b
}
func方法
//func 函数名(形参...) (返回值...){
// 函数体
//}
func add(a int, b int) int {
return a + b
}
func add2(a, b int) int {
return a + b
}
//go可以有多个返回值,ok以及err是非常常用的返回值
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
返回值error类型的err是方法多返回值的一个广泛应用,类似其他语言的异常处理机制
point指针
类似c++的引用传递和值传递,但是要注意,go里面只有值传递(类似),即使是结构体也只有传递指针才能修改结构体
import "fmt"
//n不会变化
func add2(n int) {
n += 2
}
//n会变化
func add2ptr(n *int) {
*n += 2
}
func main() {
//可以通过new一个指针,初始化时为空nil
A := new(int)
n := 5
add2(n)
fmt.Println(n) // 5
add2ptr(&n)
fmt.Println(n) // 7
}
结构体
结构体类似c++ java中的对象,go不是面向对象的语言
import "fmt"
type user struct {
name string
password string
}
func main() {
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d) // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
fmt.Println(checkPassword(a, "haha")) // false
fmt.Println(checkPassword2(&a, "haha")) // false
}
func checkPassword(u user, password string) bool {
return u.password == password
}
//注意这里需要传递user指针才能对user结构体进行修改
func checkPassword2(u *user, password string) bool {
return u.password == password
}
结构体方法
import "fmt"
type user struct {
name string
password string
}
//第一种(u user)
func (u user) checkPassword(password string) bool {
return u.password == password
}
//第二种(u *user)用于修改结构体
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
error异常
go的异常处理机制相比java和c++要简单的多,nil一般表示空,即无异常
import (
"errors"
"fmt"
)
type user struct {
name string
password string
}
func findUser(users []user, name string) (v *user, err error) {
//结构体切片users
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
//异常非空,异常处理
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
string的一些操作方法
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // true
fmt.Println(strings.Count(a, "l")) // 2
fmt.Println(strings.HasPrefix(a, "he")) // true
fmt.Println(strings.HasSuffix(a, "llo")) // true
fmt.Println(strings.Index(a, "ll")) // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2)) // hellohello
fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
fmt.Println(strings.ToLower(a)) // hello
fmt.Println(strings.ToUpper(a)) // HELLO
fmt.Println(len(a)) // 5
b := "你好"
fmt.Println(len(b)) // 6中文字符串的长度
格式化打印fmf流
import "fmt"
type point struct {
x, y int
}
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123 联合打印
fmt.Println(p) // {1 2} 打印结构体
// 这里\n替代了Println的回车
fmt.Printf("s=%v\n", s) // s=hello 打印值,等价于不带参数s=%v\n,以默认的方式打印变量的值
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2} 打印时会显示结构体名
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2} 打印时会同时显示包名
f := 3.141592653
fmt.Println(f) // 3.141592653
fmt.Printf("%.2f\n", f) // 3.14 %.2f 保留两位小数
json的使用
Go开发人员经常需要处理JSON内容。例如,我们经常要读取JSON文件来填充Go对象,并从现有的Go对象中写入JSON文件。像其他现代编程语言一样,Go提供了一个标准库模块来处理JSON结构。
Go提供了encoding/json包,通过标准库的编码命名空间处理JSON内容。encoding/json包提供了API函数,用于从Go对象生成JSON文档--以及从JSON文档中填充Go对象。此外,它还允许你定制JSON到Go和Go到JSON的翻译过程。
将Go对象编码为JSON格式被称为marshaling。我们可以使用Marshal 函数来将 Go 对象转换为 JSON。Marshal 函数的语法如下。将一个go结构体转化为byte数组。
func Marshal(v interface{}) ([]byte, error)
使用map构造json
package main
import (
"fmt"
"encoding/json"
)
func main() {
fileCount := map[string]int{
"cpp": 10,
"js": 8,
"go": 10,
}
bytes, _ := json.Marshal(fileCount)
fmt.Println(string(bytes))
}
使用结构体构造json:
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(buf) // [123 34 78 97...] 输出字节数组
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
输出格式化的json:json.MarshalIndent(a, "", "\t")
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
json的解码:json.Unmarshal(buf, &b)
注意这里要传入结构体的引用才能返回json的go结构体
var b userInfo
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}
time时间的使用
go提供了time包处理时间数据
time.Time类型表示时间。我们可以通过time.Now()函数获取当前的时间对象,然后获取时间对象的年月日时分秒等信息。
时间类型有一个自带的方法Format进行格式化,需要注意的是Go语言中格式化时间模板不是常见的Y-m-d H:M:S而是使用Go的诞生时间2006年1月2号15点04分。
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36"):使用指定的格式字符串"2006-01-02 15:04:05"来解析字符串"2022-03-27 01:25:36",并将结果赋值给变量t3。如果解析失败,err会被赋值为非nil值。
fmt.Println(now.Unix()):打印当前时间的Unix时间戳(从1970年1月1日00:00:00 UTC到当前时间的秒数)。
示例代码如下:
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
//设置时区为UTC
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
diff := t2.Sub(t)
fmt.Println(diff) // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) // true
fmt.Println(now.Unix()) // 1648738080
}
string与数字的转化
f, _ := strconv.ParseFloat("1.234", 64) 将字符串转化为float,指定以64位存储
n, _ := strconv.ParseInt("111", 10, 64) 指定以10进制转化为int
strconv.Atoi 自动转化,如果不符合规范则返回错误信息
import (
"fmt"
"strconv"
)
func main() {
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}
环境相关
import (
"fmt"
"os"
"os/exec"
)
func main() {
// go run example/20-env/main.go a b c d
fmt.Println(os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
//设置环境变量
fmt.Println(os.Setenv("AA", "BB"))
这是使用exec.Command()执行在linux下的grep命令,后面附带grep的参数,CombinedOutput()返回命令运行的结果(以字节数组存储)
在文件 file.txt 中查找字符串 "hello",并打印匹配的行:grep hello file.txt
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1 localhost
}