一些练习题,简单回顾一下六到八节的内容
排序、
一起学习
排序
package main
import (
"fmt"
"sort"
)
func main() {
strs := []string{"c", "a", "b"}
sort.Strings(strs)//数组排序
fmt.Println("Strings:", strs)
ints := []int{7, 2, 4}
sort.Ints(ints)//数组排序
fmt.Println("Ints: ", ints)
//是否排好序
s := sort.IntsAreSorted(ints)
fmt.Println("Sorted: ", s)
}
Strings: [a b c]
Ints: [2 4 7]
Sorted: true
使用函数自定义排序
有时候,我们可能想根据自然顺序以外的方式来对集合进行排序。
例如,假设我们要按字符串的长度而不是按字母顺序对它们进行排序。
这儿有一个在 Go 中自定义排序的示例。
package main
import (
"fmt"
"sort"
)
// byLength 类型,它只是内建类型 []string 的别名。
type byLength []string//这里不想C语言是起别名,这里是定义了新的类型
/*
ort.Interface 接口的 Len、Less 和 Swap 方法
*/
func (s byLength) Len() int {
return len(s)
}
func (s byLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
//Less 将控制实际的自定义排序逻辑。
func (s byLength) Less(i, j int) bool {
return len(s[i]) < len(s[j])
}
func main() {
fruits := []string{"peach", "banana", "kiwi"}
//将切片 fruits 强转为 byLength 类型的切片
sort.Sort(byLength(fruits))
fmt.Println(fruits)
}
[kiwi peach banana]
别名与新类型
type MyInt1 int //新的类型
type MyInt2 = int //别名
Panic
运行程序将会导致 panic: 输出一个错误消息和协程追踪信息,并以非零的状态退出程序。
注意,与某些使用 exception 处理错误的语言不同, 在 Go 中,通常会尽可能的使用返回值来标示错误。
package main
import "os"
func main() {
panic("a problem")
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}
panic: a problem
goroutine 1 [running]:
main.main()
/.../panic.go:12 +0x47
Defer
package main
import (
"fmt"
"os"
)
func main() {
f := createFile("/tmp/defer.txt")
defer closeFile(f)
writeFile(f)
}
func createFile(p string) *os.File {
fmt.Println("creating")
f, err := os.Create(p)
if err != nil {
panic(err)
}
return f
}
func writeFile(f *os.File) {
fmt.Println("writing")
fmt.Fprintln(f, "data")
}
func closeFile(f *os.File) {
fmt.Println("closing")
err := f.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)//err输出,最后打印
os.Exit(1)//退出程序
}
}
creating
writing
closing
Recover
必须在 defer 函数中调用 recover
。 当跳出引发 panic 的函数时,defer 会被激活, 其中的 recover
会捕获 panic
。
package main
import "fmt"
func mayPanic() {
panic("a problem")
}
func main() {
defer func() {
//recover 的返回值是在调用 panic 时抛出的错误。
if r := recover(); r != nil {
fmt.Println("Recovered. Error:\n", r)
}
}()
mayPanic()
//这行代码不会执行,因为 mayPanic 函数会调用 panic。 main 程序的执行在 panic 点停止,并在继续处理完 defer 后结束。
fmt.Println("After mayPanic()")
}
Recovered. Error:
a problem
组合函数
package main
import (
"fmt"
"strings"
)
func Index(vs []string, t string) int {
for i, v := range vs {
if v == t {
return i+1
}
}
return -1
}
func Include(vs []string, t string) bool {
return Index(vs, t) >= 0
}
func Any(vs []string, f func(string) bool) bool {
for _, v := range vs {
if f(v) {
return true
}
}
return false
}
func All(vs []string, f func(string) bool) bool {
for _, v := range vs {
if !f(v) {
return false
}
}
return true
}
func Filter(vs []string, f func(string) bool) []string {
//vsf := make([]string, 0)
vsf := []string{}
for _, v := range vs {
if f(v) {
vsf = append(vsf, v)
}
}
return vsf
}
func Map(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))
for i, v := range vs {
vsm[i] = f(v)
}
return vsm
}
func main() {
var strs = []string{"peach", "apple", "pear", "plum"}
fmt.Println(Index(strs, "pear"))
fmt.Println(Include(strs, "grape"))
//判断字符串数组中是否含有首字符是否为p的字符串
fmt.Println(Any(strs, func(v string) bool {
return strings.HasPrefix(v, "p")
}))
//判断字符串数组中是否都含有首字符是否为p的字符串
fmt.Println(All(strs, func(v string) bool {
return strings.HasPrefix(v, "p")
}))
fmt.Println(Filter(strs, func(v string) bool {
return strings.Contains(v, "e")
}))
fmt.Println(Map(strs, strings.ToUpper))
}
3
false
true
false
[peach apple pear]
[PEACH APPLE PEAR PLUM]
字符串函数
package main
import (
"fmt"
s "strings"
)
var p = fmt.Println
func main() {
p("Contains: ", s.Contains("test", "es"))
p("Count: ", s.Count("test", "t"))
p("HasPrefix: ", s.HasPrefix("test", "te"))
p("HasSuffix: ", s.HasSuffix("test", "st"))
p("Index: ", s.Index("test", "e"))
p("Join: ", s.Join([]string{"a", "b"}, "-"))
p("Repeat: ", s.Repeat("a", 5))
p("Replace: ", s.Replace("foo", "o", "0", -1))
p("Replace: ", s.Replace("foo", "o", "0", 1))
p("Split: ", s.Split("a-b-c-d-e", "-"))
p("ToLower: ", s.ToLower("TEST"))
p("ToUpper: ", s.ToUpper("test"))
p()
p("Len: ", len("hello"))
p("Char:", "hello"[1])
}
Contains: true
Count: 2
HasPrefix: true
HasSuffix: true
Index: 1
Join: a-b
Repeat: aaaaa
Replace: f00
Replace: f0o
Split: [a b c d e]
ToLower: test
ToUpper: TEST
Len: 5
Char: 101
字符串格式化
package main
import (
"fmt"
"os"
)
type point struct {
x, y int
}
func main() {
p := point{1, 2}
fmt.Printf("struct1: %v\n", p)
fmt.Printf("struct2: %+v\n", p)
fmt.Printf("struct3: %#v\n", p)
fmt.Printf("type: %T\n", p)
fmt.Printf("bool: %t\n", true)
fmt.Printf("int: %d\n", 123)
fmt.Printf("bin: %b\n", 14)
fmt.Printf("char: %c\n", 33)
fmt.Printf("hex: %x\n", 456)
fmt.Printf("float1: %f\n", 78.9)
fmt.Printf("float2: %e\n", 123400000.0)
fmt.Printf("float3: %E\n", 123400000.0)
fmt.Printf("str1: %s\n", "\"string\"")
fmt.Printf("str2: %q\n", "\"string\"")
fmt.Printf("str3: %x\n", "hex this")
fmt.Printf("pointer: %p\n", &p)
fmt.Printf("width1: |%6d|%6d|\n", 12, 345)
fmt.Printf("width2: |%6.2f|%6.2f|\n", 1.2, 3.45)
fmt.Printf("width3: |%-6.2f|%-6.2f|\n", 1.2, 3.45)
fmt.Printf("width4: |%6s|%6s|\n", "foo", "b")
fmt.Printf("width5: |%-6s|%-6s|\n", "foo", "b")
s := fmt.Sprintf("sprintf: a %s", "string")
fmt.Println(s)
fmt.Fprintf(os.Stderr, "io: an %s\n", "error")
}
struct1: {-1 2}
struct2: {x:-1 y:2}
struct3: main.point{x:-1, y:2}
type: main.point
bool: true
int: 123
bin: 1110
char: !
hex: 1c8
float1: 78.900000
float2: 1.234000e+08
float3: 1.234000E+08
str1: "string"
str2: "\"string\""
str3: 6865782074686973
pointer: 0xc00000a0c0
width1: | 12| 345|
width2: | 1.20| 3.45|
width3: |1.20 |3.45 |
width4: | foo| b|
width5: |foo |b |
sprintf: a string
io: an error
正则表达式
后面的一些API没有了解
package main
import (
"bytes"
"fmt"
"regexp"
)
func main() {
match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
fmt.Println(match)
r, _ := regexp.Compile("p([a-z]+)ch")
fmt.Println(r.MatchString("peach"))
//查找匹配的字符串。
fmt.Println(r.FindString("peach punch"))
//匹配开始和结束位置的索引 idx: [0 5]
fmt.Println("idx:", r.FindStringIndex("peach punch"))
//Submatch 返回完全匹配和局部匹配的字符串 [peach ea]
fmt.Println(r.FindStringSubmatch("peach punch"))
//[0 5 1 3]
fmt.Println(r.FindStringSubmatchIndex("peach punch"))
//非负整数作为第二个参数,来限制匹配次数。负数就是匹配全部
fmt.Println(r.FindAllString("peach punch pinch", -1))
fmt.Println("all:", r.FindAllStringSubmatchIndex(
"peach punch pinch", -1))
fmt.Println(r.FindAllString("peach punch pinch", 2))
fmt.Println(r.Match([]byte("peach")))
r = regexp.MustCompile("p([a-z]+)ch")
fmt.Println("regexp:", r)
fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
in := []byte("a peach")
out := r.ReplaceAllFunc(in, bytes.ToUpper)
fmt.Println(string(out))
}
true
true
peach
idx: [0 5]
[peach ea]
[0 5 1 3]
[peach punch pinch]
all: [[0 5 1 3] [6 11 7 9] [12 17 13 15]]
[peach punch]
true
regexp: p([a-z]+)ch
a <fruit>
a PEACH
JSON
package main
import (
"encoding/json"
"fmt"
"os"
)
type response1 struct {
Page int
Fruits []string
}
type response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
func main() {
bolB, _ := json.Marshal(true)
fmt.Println(string(bolB))
intB, _ := json.Marshal(1)
fmt.Println(string(intB))
fltB, _ := json.Marshal(2.34)
fmt.Println(string(fltB))
strB, _ := json.Marshal("gopher")
//"gopher"
fmt.Println(string(strB))
slcD := []string{"apple", "peach", "pear"}
slcB, _ := json.Marshal(slcD)
//["apple","peach","pear"]
fmt.Println(string(slcB))
mapD := map[string]int{"apple": 5, "lettuce": 7}
mapB, _ := json.Marshal(mapD)
//{"apple":5,"lettuce":7}
fmt.Println(string(mapB))
res1D := &response1{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res1B, _ := json.Marshal(res1D)
//{"Page":1,"Fruits":["apple","peach","pear"]}
fmt.Println(string(res1B))
res2D := &response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
//{"page":1,"fruits":["apple","peach","pear"]} 这里的小写是struct设定的
fmt.Println(string(res2B))
//模拟json转码后的格式
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
//提供一个 JSON 包可以存放解码数据的变量
var dat map[string]interface{}
//判断解码是否成功
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
//map[num:6.13 strs:[a b]]
fmt.Println(dat)
num := dat["num"].(float64)//因为是interface可以断言
//6.13
fmt.Println(num)
strs := dat["strs"].([]interface{})
str1 := strs[0].(string)
//a
fmt.Println(str1)
//使用案例
str := `{"page": 1, "fruits": ["apple", "peach"]}`
//承接JSON格式的结构体
res := response2{}
//解码
json.Unmarshal([]byte(str), &res)
//{1 [apple peach]}
fmt.Println(res)
//apple
fmt.Println(res.Fruits[0])
// os.Stdout 一样直接将 JSON 编码流传输到 os.Writer
enc := json.NewEncoder(os.Stdout)//直接转码到stdout
d := map[string]int{"apple": 5, "lettuce": 7}
//转码
enc.Encode(d)//直接转码到stdout {"apple":5,"lettuce":7}
}
时间
/**
@Go version: 1.17.6
@project: TeachCode
@ide: GoLand
@file: timeApi.go
@author: Lido
@time: 2022-03-03 14:36
@description: Time
*/
package main
import (
"fmt"
"time"
)
func main() {
p := fmt.Println
now := time.Now()
p(now)
then := time.Date(
2009, 11, 17, 20, 34, 58, 651387237, time.Local)
p(then)
p(then.Year())//2009
p(then.Month())//11
p(then.Day())//17
p(then.Hour())
p(then.Minute())
p(then.Second())
p(then.Nanosecond())
p(then.Location())
p(then.Weekday())//Tuesday
p(then.Before(now))//true
p(then.After(now))//false
p(then.Equal(now))//false
diff := now.Sub(then)//方法 Sub 返回一个 Duration 来表示两个时间点的间隔时间
p(diff)//时间差 107730h2m13.696547563s
p(diff.Hours())//以小时表示这段时间 107730.03713792987
p(diff.Minutes())
p(diff.Seconds())
p(diff.Nanoseconds())
p(then.Add(diff))//减去一段时间
p(then.Add(-diff))//增加一段时间
}
2022-03-03 14:37:12.3479348 +0800 CST m=+0.003808501
2009-11-17 20:34:58.651387237 +0800 CST
2009
November
17
20
34
58
651387237
Local
Tuesday
true
false
false
107730h2m13.696547563s
107730.03713792987
6.463802228275793e+06
3.8782813369654757e+08
387828133696547563
2022-03-03 14:37:12.3479348 +0800 CST
1997-08-04 02:32:44.954839674 +0800 CST
时间戳
package main
import (
"fmt"
"time"
)
func main() {
//1970年1月1日0点作为“unix纪元”的原点
now := time.Now()
secs := now.Unix() //秒
nanos := now.UnixNano() //纳秒
fmt.Println(now)
millis := nanos / 1000000 //通多换算纳秒来得到毫秒,因为用秒会不太精确
fmt.Println("secs ", secs)
fmt.Println("millis", millis)
fmt.Println("nanos ", nanos)
//将 Unix 纪元起的整数秒或者纳秒转化到相应的时间
fmt.Println(time.Unix(secs, 0))
fmt.Println(time.Unix(0, nanos))
}
2022-03-03 14:56:51.977756 +0800 CST m=+0.002675301
secs 1646290611
millis 1646290611977
nanos 1646290611977756000
2022-03-03 14:56:51 +0800 CST
2022-03-03 14:56:51.977756 +0800 CST
时间的格式化和解析
这个用的时候要记得
package main
import (
"fmt"
"time"
)
func main() {
p := fmt.Println
t := time.Now()
p(t.Format(time.RFC3339))
t1, e := time.Parse(
time.RFC3339,
"2012-11-01T22:08:41+00:00")
p(t1)
p(t.Format("3:04PM"))
p(t.Format("Mon Jan _2 15:04:05 2006"))
p(t.Format("2006-01-02T15:04:05.999999-07:00"))
form := "3 04 PM"
t2, e := time.Parse(form, "8 41 PM")
p(t2)
fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second())
ansic := "Mon Jan _2 15:04:05 2006"
_, e = time.Parse(ansic, "8:41PM")
p(e)
}
2022-03-03T15:02:48+08:00
2012-11-01 22:08:41 +0000 +0000
3:02PM
Thu Mar 3 15:02:48 2022
2022-03-03T15:02:48.660809+08:00
t2 0000-01-01 20:41:00 +0000 UTC
2022-03-03T15:02:48-00:00
parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": cannot parse "8:41PM" as "Mon"
随机数
/**
@Go version: 1.17.6
@project: TeachCode
@ide: GoLand
@file: rand.go
@author: Lido
@time: 2022-03-03 15:10
@description: Go随机数
*/
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Print(rand.Intn(100), ",")
fmt.Print(rand.Intn(100))
fmt.Println()
// 0.0 <= f < 1.0
fmt.Println(rand.Float64())
//范围随机数
fmt.Print((rand.Float64()*5)+5, ",")
fmt.Print((rand.Float64() * 5) + 5)
fmt.Println()
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
fmt.Print(r1.Intn(100), ",")
fmt.Print(r1.Intn(100))
fmt.Println()
/**
使用自定义的种子,如果相同则随机数会相同
*/
s2 := rand.NewSource(42) //自定义种子
r2 := rand.New(s2) //使用自定义的种子
fmt.Print(r2.Intn(100), ",")
fmt.Print(r2.Intn(100))
fmt.Println()
s3 := rand.NewSource(42)
r3 := rand.New(s3)
fmt.Print(r3.Intn(100), ",")
fmt.Print(r3.Intn(100))
}
数值解析
package main
import (
"fmt"
"strconv"
)
func main() {
//int64 也就是我电脑64位的默认值
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f)
i, _ := strconv.ParseInt("123", 0, 64)
fmt.Println(i)
//ParseInt 会自动识别出字符串是十六进制数。
d, _ := strconv.ParseInt("0x1c8", 0, 64)
fmt.Println(d)
u, _ := strconv.ParseUint("789", 0, 64)
fmt.Println(u)
//Atoi 是一个基础的 10 进制整型数转换函数
k, _ := strconv.Atoi("135")
fmt.Println(k)
_, e := strconv.Atoi("wat")
//strconv.Atoi: parsing "wat": invalid syntax
fmt.Println(e)
}
1.234
123
456
789
135
strconv.Atoi: parsing "wat": invalid syntax
URL 解析
这里好像常用的是协议名称和主机的分割
package main
import (
"fmt"
"net"
"net/url"
)
func main() {
s := "postgres://user1:pass@host.com:5432/path?k=v#f"
//s := "https://gobyexample-cn.github.io/url-parsing"
u, err := url.Parse(s)
if err != nil {
panic(err)
}
fmt.Println(u.Scheme)//协议名称 postgres
fmt.Println(u.User)
fmt.Println(u.User.Username())
p, _ := u.User.Password()
fmt.Println(p)
fmt.Println(u.Host)//host.com:5432
host, port, _ := net.SplitHostPort(u.Host)
fmt.Println(host)
fmt.Println(port)
//提取路径和 # 后面的查询片段信息
fmt.Println(u.Path)
fmt.Println(u.Fragment)
fmt.Println(u.RawQuery)
m, _ := url.ParseQuery(u.RawQuery)
fmt.Println(m)
fmt.Println(m["k"][0])
}
postgres
user1:pass
user1
pass
host.com:5432
host.com
5432
/path
f
k=v
map[k:[v]]
v
SHA1 哈希
package main
import (
"crypto/md5"
"crypto/sha1"
"fmt"
)
func main() {
s := "sha1 this string"
//sha1
h := sha1.New()
//md5
m := md5.New()
h.Write([]byte(s))
m.Write([]byte(s))
bs := h.Sum(nil)
md := m.Sum(nil)
fmt.Println(s)
//SHA1 值经常以 16 进制输出
fmt.Printf("%x\n", bs)
//MD5 值经常以 16 进制输出
fmt.Printf("%x\n", md)
}
cf23df2207d99a74fbe169e3eba035e633b65d94
c0b06bcc2087b93b3be71e1c1a524ce2
base64
package main
import (
b64 "encoding/base64"
"fmt"
)
func main() {
data := "abc123!?$*&()'-=@~"
//标准base64转码
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)
//标准base64解码
sDec, _ := b64.StdEncoding.DecodeString(sEnc)
fmt.Println(string(sDec))
fmt.Println("-----------------------------")
//URL base64转码
uEnc := b64.URLEncoding.EncodeToString([]byte(data))
fmt.Println(uEnc)
//URL base64解码
uDec, _ := b64.URLEncoding.DecodeString(uEnc)
fmt.Println(string(uDec))
}
YWJjMTIzIT8kKiYoKSctPUB+
abc123!?$*&()'-=@~
-----------------------------
YWJjMTIzIT8kKiYoKSctPUB-
abc123!?$*&()'-=@~
参考资料
PREVIOUSgo协程专项练习