代码如下:
package main
import "fmt"
func f(from string){
for i:=0;i<3;i++{
fmt.Println(from,":",i)
}
}
func main(){
f("direct")
go f("goroutine")
go func(msg string){
fmt.Println(msg)
}("going")
var input string
fmt.Scanln(&input)
fmt.Println("done")
}
结果如下:
direct : 0
direct : 1
direct : 2
goroutine : 0
going
goroutine : 1
goroutine : 2
done
代码如下:
package main
import "fmt"
func main(){
messages := make(chan string)
go func(){
messages <- "ping"
}()
//也可以用通道缓冲
//messages := make(chan string, 1)
//messages <- "ping"
msg := <-messages
fmt.Println(msg)
}
结果如下:
ping
代码如下:
package main
import (
"fmt"
)
func main(){
messages := make(chan string,2)
messages <- "buffered"
messages <- "channel"
fmt.Println(<-messages)
fmt.Println(<-messages)
}
结果如下:
buffered
channel
代码如下:
package main
import (
"fmt"
"time"
)
func worker(done chan bool){
fmt.Println("working...")
time.Sleep(time.Second)
fmt.Println("done")
done <- true
}
func main(){
done := make(chan bool)
go worker(done)
//也可以用通道缓冲
//done := make(chan bool, 1)
//worker(done)
<-done
}
结果如下:
working...
done
代码如下:
package main
import (
"fmt"
"time"
)
func main(){
ch1 := make(chan string)
ch2 := make(chan string)
go func(){
time.Sleep(time.Second)
ch1 <- "one"
}()
go func(){
time.Sleep(time.Second*2)
ch2 <- "two"
}()
for i:=0;i<2;i++{
select {
case msg1 := <- ch1:
fmt.Println("received",msg1)
case msg2 := <- ch2:
fmt.Println("received",msg2)
}
}
}
结果如下:
received one
received two
代码如下:
package main
import (
"fmt"
"time"
)
func main(){
c1 := make(chan string)
go func(){
time.Sleep(time.Second*2)
c1 <- "result1"
}()
select {
case res := <- c1:
fmt.Println(res)
case <- time.After(time.Second):
fmt.Println("timeout1")
}
c2 := make(chan string)
go func(){
time.Sleep(time.Second)
c2 <- "result2"
}()
select {
case res := <- c2:
fmt.Println(res)
case <- time.After(time.Second*2):
fmt.Println("timeout2")
}
}
结果如下:
timeout1
result2
代码如下:
package main
import "fmt"
func main(){
messages := make(chan string)//若有通道缓冲,则能够收到
signals := make(chan string)
select {
case msg := <- messages:
fmt.Println("received message",msg)
default:
fmt.Println("no messages received")
}
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message",msg)
default:
fmt.Println("no messages sent")
}
select {
case msg := <- messages:
fmt.Println("received message",msg)
case sig := <- signals:
fmt.Println("received signal",sig)
default:
fmt.Println("no activity")
}
}
结果如下:
no messages received
no messages sent
no activity
- 通道的关闭
代码如下:
package main
import "fmt"
func main(){
jobs := make(chan int, 5)
done := make(chan bool)
go func(){
for{
value, more := <- jobs
if more{
fmt.Println("received job",value)
}else{
fmt.Println("received all jobs")
done <- true
return
}
}
}()
for i:=1;i<=3;i++{
jobs <- i
fmt.Println("sent job",i)
}
close(jobs)
fmt.Println("sent all jobs")
<-done
}
结果如下:
sent job 1
received job 1
received job 2
sent job 2
sent job 3
sent all jobs
received job 3
received all jobs
- 通道遍历
代码如下:
package main
import "fmt"
func main(){
queue := make(chan string, 2)
queue <- "one"
queue <- "two"
close(queue)
for elem := range queue{
fmt.Println(elem)
}
}
结果如下:
one
two
- 定时器
代码如下:
package main
import (
"fmt"
"time"
)
func main(){
timer1 := time.NewTimer(time.Second)
<-timer1.C
fmt.Println("Timer1 expired")
timer2 := time.NewTimer(time.Second)
go func(){
<-timer2.C
fmt.Println("Timer2 expired")
}()
timer2.Stop()
fmt.Println("Timer2 stopped")
}
结果如下:
Timer1 expired
Timer2 stopped
- 打点器
代码如下:
package main
import (
"fmt"
"time"
)
func main(){
ticker := time.NewTicker(time.Millisecond*500)
go func(){
for i := range ticker.C{
fmt.Println("Tick at",i)
}
}()
time.Sleep(time.Millisecond*1600)
ticker.Stop()
fmt.Println("Ticker stopped")
}
结果如下:
Tick at 2018-11-22 11:11:08.8536293 +0800 CST m=+0.506127601
Tick at 2018-11-22 11:11:09.3536449 +0800 CST m=+1.006143201
Tick at 2018-11-22 11:11:09.8539063 +0800 CST m=+1.506404601
Ticker stopped
- 工作池
代码如下:
package main
import (
"fmt"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int){
for i := range jobs{
fmt.Println("worker",id,"processing job",i)
time.Sleep(time.Second)
results <- i*2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for m:=1;m<=3;m++{
go worker(m,jobs,results)
}
for i:=1;i<=9;i++{
jobs <- i
}
close(jobs)
for j:=1;j<=9;j++{
<- results
}
}
结果如下:
worker 2 processing job 2
worker 1 processing job 1
worker 3 processing job 3
worker 1 processing job 4
worker 2 processing job 5
worker 3 processing job 6
worker 2 processing job 7
worker 1 processing job 8
worker 3 processing job 9
代码如下:
package main
import (
"fmt"
"time"
)
func main() {
requests := make(chan int,5)
for i:=1;i<=5;i++{
requests <- i
}
close(requests)
limiter := time.Tick(time.Millisecond*200)
for req := range requests{
<-limiter
fmt.Println("request",req,time.Now())
}
burstyLimiter := make(chan time.Time,3)
for i:=1;i<=3;i++{
burstyLimiter <- time.Now()
}
go func() {
t := time.Tick(time.Millisecond*200)
for i := range t{
burstyLimiter <- i
}
}()
burstyRequests := make(chan int,5)
for j:=1;j<=5;j++{
burstyRequests <- j
}
close(burstyRequests)
for req := range burstyRequests{
<- burstyLimiter//tn := <- burstyLimiter
fmt.Println("request",req,time.Now())//fmt.Println("request",req,tn)
}
}
结果如下:
request 1 2018-11-22 13:31:12.5932522 +0800 CST m=+0.208619801
request 2 2018-11-22 13:31:12.793778 +0800 CST m=+0.409145601
request 3 2018-11-22 13:31:12.9931922 +0800 CST m=+0.608559801
request 4 2018-11-22 13:31:13.1937051 +0800 CST m=+0.809072801
request 5 2018-11-22 13:31:13.393264 +0800 CST m=+1.008631601
request 1 2018-11-22 13:31:13.393264 +0800 CST m=+1.008631601
request 2 2018-11-22 13:31:13.393264 +0800 CST m=+1.008631601
request 3 2018-11-22 13:31:13.393264 +0800 CST m=+1.008631601
request 4 2018-11-22 13:31:13.5933922 +0800 CST m=+1.208759901
request 5 2018-11-22 13:31:13.7938431 +0800 CST m=+1.409210701
package main
import (
"fmt"
"runtime"
"sync/atomic"
"time"
)
func main() {
var ops uint64 = 0
for i:=0;i<50;i++{
go func() {
for{
atomic.AddUint64(&ops,1)
runtime.Gosched()//让出CPU时间片
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:",opsFinal)
}
结果如下:
ops: 3139216
代码如下:
package main
import (
"fmt"
"math/rand"
"runtime"
"sync"
"sync/atomic"
"time"
)
func main() {
var state = make(map[int]int)
var mutex = &sync.Mutex{}
var ops uint64 = 0
for m:=0;m<10;m++{
go func() {
for{
key := rand.Intn(5)
val := rand.Intn(100)
mutex.Lock()
state[key]=val
mutex.Unlock()
atomic.AddUint64(&ops,1)
runtime.Gosched()
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:",opsFinal)
mutex.Lock()
fmt.Println(state)
mutex.Unlock()
}
结果如下:
ops: 2072334
map[1:65 0:85 2:25 4:65 3:54]
- Go状态协程
代码如下:
package main
import (
"fmt"
"math/rand"
"sync/atomic"
"time"
)
type readOp struct {
key int
resp chan int
}
type writeOp struct {
key int
val int
resp chan bool
}
func main() {
var ops uint64
reads := make(chan *readOp)
writes := make(chan *writeOp)
go func() {
var state = make(map[int]int)
for{
select {
case read := <- reads:
read.resp <- state[read.key]
case write := <- writes:
state[write.key] = write.val
write.resp <- true
}
}
}()
for r:=0;r<100;r++{
go func() {
for {
read := &readOp{
rand.Intn(5),
make(chan int)}
reads <- read
<-read.resp
atomic.AddUint64(&ops, 1)
}
//runtime.Gosched()
}()
}
for w:=0;w<10;w++{
go func() {
for{
write := &writeOp{
rand.Intn(5),
rand.Intn(100),
make(chan bool)}
writes <- write
<- write.resp
atomic.AddUint64(&ops,1)
}
//runtime.Gosched()
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:",opsFinal)
}
结果如下:
ops: 601082
- 排序
代码如下:
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
- 使用函数自定义排序
package main
import (
"fmt"
"sort"
)
type ByLength []string
func (s ByLength) Len() int{
return len(s)
}
func (s ByLength) Less(i,j int) bool{
return len(s[i])<len(s[j])
}
func (s ByLength) Swap(i,j int) {
s[i], s[j] = s[j], s[i]
}
func main(){
s := []string{"hanmingyu","hanmy","hmy"}
sort.Sort(ByLength(s))
fmt.Println(s)
}
结果如下:
[hmy hanmy hanmingyu]
- Panic
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()
D:/GOPATH/src/awesomeProject/example/main/main.go:6 +0x40
Process finished with exit code 2
- Defer
代码如下:
package main
import (
"fmt"
"os"
)
func main(){
f := createFile("D:/GOPATH/src/awesomeProject/example/main/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")
f.Close()
}
结果如下:
creating
writing
closing
- 组合函数
代码如下:
package main
import (
"fmt"
"strings"
)
//返回目标字符串 t 出现的的第一个索引位置,或者在没有匹配值时返回 -1。
func Index(vs []string, t string) int{
for i,v := range vs{
if v==t{
return i
}
}
return -1
}
//如果目标字符串 t 在这个切片中则返回 true。
func Include(vs []string, t string) bool{
return Index(vs,t)>=0
}
//如果这些切片中的字符串有一个满足条件 f 则返回true。
func Any(vs []string, f func(string) bool) bool{
for _,v := range vs{
if f(v){
return true
}
}
return false
}
//如果切片中的所有字符串都满足条件 f 则返回 true。
func All(vs []string, f func(string) bool) bool{
for _,v := range vs{
if !f(v){
return false
}
}
return true
}
//返回一个包含所有切片中满足条件 f 的字符串的新切片。
func Filter(vs []string, f func(string) bool) []string{
s := []string{}//s := make([]string,0)
for _,v := range vs{
if f(v){
s = append(s,v)
}
}
return s
}
//返回一个对原始切片中所有字符串执行函数 f 后的新切片。
func Map(vs []string, f func(string) string) []string{
s := []string{}//s := make([]string,0)
for _,v := range vs{
s = append(s,f(v))
}
return s
}
func main() {
var strs = []string{"peach", "apple", "pear", "plum"}
fmt.Println(Index(strs, "pear"))
fmt.Println(Include(strs, "grape"))
fmt.Println(Any(strs, func(v string) bool {
return strings.HasPrefix(v, "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))
}
结果如下:
2
false
true
false
[peach apple pear]
[PEACH APPLE PEAR PLUM]
- 字符串函数
代码如下:
package main
import "fmt"
import 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(){
//Go 为常规 Go 值的格式化设计提供了多种打印方式。例如,这里打印了 point 结构体的一个实例。
p := point{1, 2}
fmt.Printf("%v\n", p)
//如果值是一个结构体,%+v 的格式化输出内容将包括结构体的字段名。
fmt.Printf("%+v\n", p)
//%#v 形式则输出这个值的 Go 语法表示。例如,值的运行源代码片段。
fmt.Printf("%#v\n", p)
//需要打印值的类型,使用 %T。
fmt.Printf("%T\n", p)
//格式化布尔值是简单的。
fmt.Printf("%t\n", true)
//格式化整形数有多种方式,使用 %d进行标准的十进制格式化。
fmt.Printf("%d\n", 123)
//这个输出二进制表示形式。
fmt.Printf("%b\n", 14)
//这个输出给定整数的对应字符。
fmt.Printf("%c\n", 33)
//%x 提供十六进制编码。
fmt.Printf("%x\n", 456)
//对于浮点型同样有很多的格式化选项。使用 %f 进行最基本的十进制格式化。
fmt.Printf("%f\n", 78.9)
//%e 和 %E 将浮点型格式化为(稍微有一点不同的)科学技科学记数法表示形式。
fmt.Printf("%e\n", 123400000.0)
fmt.Printf("%E\n", 123400000.0)
//使用 %s 进行基本的字符串输出。
fmt.Printf("%s\n", "\"string\"")
//像 Go 源代码中那样带有双引号的输出,使用 %q。
fmt.Printf("%q\n", "\"string\"")
//和上面的整形数一样,%x 输出使用 base-16 编码的字符串,每个字节使用 2 个字符表示。
fmt.Printf("%x\n", "hex this")
//要输出一个指针的值,使用 %p。
fmt.Printf("%p\n", &p)
//当输出数字的时候,你将经常想要控制输出结果的宽度和精度,可以使用在 % 后面使用数字来控制输出宽度。默认结果使用右对齐并且通过空格来填充空白部分。
fmt.Printf("|%6d|%6d|\n", 12, 345)
//你也可以指定浮点型的输出宽度,同时也可以通过 宽度.精度 的语法来指定输出的精度。
fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
//要左对齐,使用 - 标志。
fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
//你也许也想控制字符串输出时的宽度,特别是要确保他们在类表格输出时的对齐。这是基本的右对齐宽度表示。
fmt.Printf("|%6s|%6s|\n", "foo", "b")
//要左对齐,和数字一样,使用 - 标志。
fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
//到目前为止,我们已经看过 Printf了,它通过 os.Stdout输出格式化的字符串。Sprintf 则格式化并返回一个字符串而不带任何输出。
s := fmt.Sprintf("a %s", "string")
fmt.Println(s)
//你可以使用 Fprintf 来格式化并输出到 io.Writers而不是 os.Stdout。
fmt.Fprintf(os.Stderr, "an %s\n", "error")
}
结果如下:
{1 2}
an error
{x:1 y:2}
main.point{x:1, y:2}
main.point
true
123
1110
!
1c8
78.900000
1.234000e+08
1.234000E+08
"string"
"\"string\""
6865782074686973
0xc0420080d0
| 12| 345|
| 1.20| 3.45|
|1.20 |3.45 |
| foo| b|
|foo |b |
a string
- 正则表达式
代码如下:
package main
import (
"bytes"
"fmt"
"regexp"
)
func main(){
//这个测试一个字符串是否符合一个表达式。
match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
fmt.Println(match)
//上面我们是直接使用字符串,但是对于一些其他的正则任务,你需要 Compile 一个优化的 Regexp 结构体。
r, _ := regexp.Compile("p([a-z]+)ch")
//这个结构体有很多方法。这里是类似我们前面看到的一个匹配测试。
fmt.Println(r.MatchString("peach"))
//这是查找匹配字符串的。
fmt.Println(r.FindString("peach punch"))
//这个也是查找第一次匹配的字符串的,但是返回的匹配开始和结束位置索引,而不是匹配的内容。
fmt.Println(r.FindStringIndex("peach punch"))
//Submatch 返回完全匹配和局部匹配的字符串。例如,这里会返回 p([a-z]+)ch 和 `([a-z]+) 的信息。
fmt.Println(r.FindStringSubmatch("peach punch"))
//类似的,这个会返回完全匹配和局部匹配的索引位置。
fmt.Println(r.FindStringSubmatchIndex("peach punch"))
//带 All 的这个函数返回所有的匹配项,而不仅仅是首次匹配项。例如查找匹配表达式的所有项。
fmt.Println(r.FindAllString("peach punch pinch", -1))
//All 同样可以对应到上面的所有函数。
fmt.Println(r.FindAllStringSubmatchIndex(
"peach punch pinch", -1))
//这个函数提供一个正整数来限制匹配次数。
fmt.Println(r.FindAllString("peach punch pinch", 2))
//上面的例子中,我们使用了字符串作为参数,并使用了如 MatchString 这样的方法。我们也可以提供 []byte参数并将 String 从函数命中去掉。
fmt.Println(r.Match([]byte("peach")))
//创建正则表示式常量时,可以使用 Compile 的变体MustCompile 。因为 Compile 返回两个值,不能用于常量。
r = regexp.MustCompile("p([a-z]+)ch")
fmt.Println(r)
//regexp 包也可以用来替换部分字符串为其他值。
fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
//Func 变量允许传递匹配内容到一个给定的函数中,
in := []byte("a peach")
out := r.ReplaceAllFunc(in, bytes.ToUpper)
fmt.Println(string(out))
}
结果如下:
true
true
peach
[0 5]
[peach ea]
[0 5 1 3]
[peach punch pinch]
[[0 5 1 3] [6 11 7 9] [12 17 13 15]]
[peach punch]
true
p([a-z]+)ch
a <fruit>
a PEACH
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(){
//首先我们来看一下基本数据类型到 JSON 字符串的编码过程。这里是一些原子值的例子。
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")
fmt.Println(string(strB))
//这里是一些切片和 map 编码成 JSON 数组和对象的例子。
slcD := []string{"apple", "peach", "pear"}
slcB, _ := json.Marshal(slcD)
fmt.Println(string(slcB))
mapD := map[string]int{"apple": 5, "lettuce": 7}
mapB, _ := json.Marshal(mapD)
fmt.Println(string(mapB))
//JSON 包可以自动的编码你的自定义类型。编码仅输出可导出的字段,并且默认使用他们的名字作为 JSON 数据的键。
res1D := &Response1{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res1B, _ := json.Marshal(res1D)
fmt.Println(string(res1B))
//你可以给结构字段声明标签来自定义编码的 JSON 数据键名称。在上面 Response2 的定义可以作为这个标签这个的一个例子。
res2D := Response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))
//现在来看看解码 JSON 数据为 Go 值的过程。这里是一个普通数据结构的解码例子。
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
//我们需要提供一个 JSON 包可以存放解码数据的变量。这里的 map[string]interface{} 将保存一个 string 为键,值为任意值的map。
var dat map[string]interface{}
//这里就是实际的解码和相关的错误检查。
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
//为了使用解码 map 中的值,我们需要将他们进行适当的类型转换。例如这里我们将 num 的值转换成 float64类型。
num := dat["num"].(float64)
fmt.Println(num)
//访问嵌套的值需要一系列的转化。
strs := dat["strs"].([]interface{})
str1 := strs[0].(string)
fmt.Println(str1)
//我们也可以解码 JSON 值到自定义类型。这个功能的好处就是可以为我们的程序带来额外的类型安全加强,并且消除在访问数据时的类型断言。
str := `{"page": 1, "fruits": ["apple", "peach"]}`
res := &Response2{}
json.Unmarshal([]byte(str), &res)
fmt.Println(res)
fmt.Println(res.Fruits[0])
//在上面的例子中,我们经常使用 byte 和 string 作为使用标准输出时数据和 JSON 表示之间的中间值。我们也可以和os.Stdout 一样,直接将 JSON 编码直接输出至 os.Writer流中,或者作为 HTTP 响应体。
enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple": 5, "lettuce": 7}
enc.Encode(d)
}
结果如下:
true
1
2.34
"gopher"
["apple","peach","pear"]
{"apple":5,"lettuce":7}
{"Page":1,"Fruits":["apple","peach","pear"]}
{"page":1,"fruits":["apple","peach","pear"]}
map[strs:[a b] num:6.13]
6.13
a
&{1 [apple peach]}
apple
{"apple":5,"lettuce":7}
- 时间
代码如下:
package main
import (
"fmt"
"time"
)
func main(){
p := fmt.Println
//得到当前时间。
now := time.Now()
p(now)
//通过提供年月日等信息,你可以构建一个 time。时间总是关联着位置信息,例如时区。
then := time.Date(
2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
p(then)
//你可以提取出时间的各个组成部分。
p(then.Year())
p(then.Month())
p(then.Day())
p(then.Hour())
p(then.Minute())
p(then.Second())
p(then.Nanosecond())
p(then.Location())
//输出是星期一到日的 Weekday 也是支持的。
p(then.Weekday())
//这些方法来比较两个时间,分别测试一下是否是之前,之后或者是同一时刻,精确到秒。
p(then.Before(now))
p(then.After(now))
p(then.Equal(now))
//方法 Sub 返回一个 Duration 来表示两个时间点的间隔时间。
diff := now.Sub(then)
p(diff)
//我们计算出不同单位下的时间长度值。
p(diff.Hours())
p(diff.Minutes())
p(diff.Seconds())
p(diff.Nanoseconds())
//你可以使用 Add 将时间后移一个时间间隔,或者使用一个 - 来将时间前移一个时间间隔。
p(then.Add(diff))
p(then.Add(-diff))
}
结果如下:
2018-11-22 19:13:53.5523728 +0800 CST m=+0.005076301
2009-11-17 20:34:58.651387237 +0000 UTC
2009
November
17
20
34
58
651387237
UTC
Tuesday
true
false
false
78998h38m54.900985563s
78998.64858360711
4.739918915016426e+06
2.8439513490098554e+08
284395134900985563
2018-11-22 11:13:53.5523728 +0000 UTC
2000-11-13 05:56:03.750401674 +0000 UTC
- 时间戳
代码如下:
package main
import (
"fmt"
"time"
)
func main(){
//分别使用带 Unix 或者 UnixNano 的 time.Now来获取从自协调世界时起到现在的秒数或者纳秒数。
now := time.Now()
secs := now.Unix()
nanos := now.UnixNano()
fmt.Println(now)
//注意 UnixMillis 是不存在的,所以要得到毫秒数的话,你要自己手动的从纳秒转化一下。
millis := nanos / 1000000
fmt.Println(secs)
fmt.Println(millis)
fmt.Println(nanos)
//你也可以将协调世界时起的整数秒或者纳秒转化到相应的时间。
fmt.Println(time.Unix(secs, 0))
fmt.Println(time.Unix(0, nanos))
}
结果如下:
2018-11-22 19:18:49.4598433 +0800 CST m=+0.008107401
1542885529
1542885529459
1542885529459843300
2018-11-22 19:18:49 +0800 CST
2018-11-22 19:18:49.4598433 +0800 CST
- 时间的格式化和解析
代码如下:
package main
import (
"fmt"
"time"
)
func main(){
p := fmt.Println
//这里是一个基本的按照 RFC3339 进行格式化的例子,使用对应模式常量。
t := time.Now()
p(t.Format(time.RFC3339))
//时间解析使用同 Format 相同的形式值。
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())
//Parse 函数在输入的时间格式不正确是会返回一个错误。
ansic := "Mon Jan _2 15:04:05 2006"
_, e = time.Parse(ansic, "8:41PM")
p(e)
}
结果如下:
2018-11-22T19:22:59+08:00
2012-11-01 22:08:41 +0000 +0000
7:22PM
Thu Nov 22 19:22:59 2018
2018-11-22T19:22:59.922421+08:00
0000-01-01 20:41:00 +0000 UTC
2018-11-22T19:22:59-00:00
parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": cannot parse "8:41PM" as "Mon"
- 随机数
代码如下:
package main
import (
"fmt"
"math/rand"
"time"
)
func main(){
fmt.Print(rand.Intn(100), ",")
fmt.Print(rand.Intn(100))
fmt.Println()
//rand.Float64 返回一个64位浮点数 f,0.0 <= f <= 1.0。
fmt.Println(rand.Float64())
//这个技巧可以用来生成其他范围的随机浮点数,例如5.0 <= f <= 10.0
fmt.Print((rand.Float64()*5)+5, ",")
fmt.Print((rand.Float64() * 5) + 5)
fmt.Println()
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
//调用上面返回的 rand.Source 的函数和调用 rand 包中函数是相同的。
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))
}
结果如下:
81,87
0.6645600532184904
7.1885709359349015,7.123187485356329
89,71
5,87
5,87
- 数字解析
代码如下:
package main
import (
"fmt"
"strconv"
)
func main(){
//使用 ParseFloat 解析浮点数,这里的 64 表示表示解析的数的位数。
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f)
//在使用 ParseInt 解析整形数时,例子中的参数 0 表示自动推断字符串所表示的数字的进制。64 表示返回的整形数是以 64 位存储的。
i, _ := strconv.ParseInt("123", 0, 64)
fmt.Println(i)
//ParseInt 会自动识别出十六进制数。
d, _ := strconv.ParseInt("0x1c8", 0, 64)
fmt.Println(d)
//ParseUint 也是可用的。
u, _ := strconv.ParseUint("789", 0, 64)
fmt.Println(u)
//Atoi 是一个基础的 10 进制整型数转换函数。
k, _ := strconv.Atoi("135")
fmt.Println(k)
//在输入错误时,解析函数会返回一个错误。
_, e := strconv.Atoi("wat")
fmt.Println(e)
}
结果如下:
1.234
123
456
789
135
strconv.Atoi: parsing "wat": invalid syntax
- URL解析
代码如下:
package main
import (
"fmt"
"net/url"
"strings"
)
func main(){
//我们将解析这个 URL 示例,它包含了一个 scheme,认证信息,主机名,端口,路径,查询参数和片段。
s := "postgres://user:pass@host.com:5432/path?k=v#f"
//解析这个 URL 并确保解析没有出错。
u, err := url.Parse(s)
if err != nil {
panic(err)
}
//直接访问 scheme。
fmt.Println(u.Scheme)
//User 包含了所有的认证信息,这里调用 Username和 Password 来获取独立值。
fmt.Println(u.User)
fmt.Println(u.User.Username())
p, _ := u.User.Password()
fmt.Println(p)
//Host 同时包括主机名和端口信息,如过端口存在的话,使用 strings.Split() 从 Host 中手动提取端口。
fmt.Println(u.Host)
h := strings.Split(u.Host, ":")
fmt.Println(h[0])
fmt.Println(h[1])
//这里我们提出路径和查询片段信息。
fmt.Println(u.Path)
fmt.Println(u.Fragment)
//要得到字符串中的 k=v 这种格式的查询参数,可以使用 RawQuery 函数。你也可以将查询参数解析为一个map。
fmt.Println(u.RawQuery)
m, _ := url.ParseQuery(u.RawQuery)
fmt.Println(m)
fmt.Println(m["k"][0])
}
结果如下:
postgres
user:pass
user
pass
host.com:5432
host.com
5432
/path
f
k=v
map[k:[v]]
v
- SHA1散列
package main
import (
"crypto/sha1"
"fmt"
)
func main(){
s := "i love cyj"
h := sha1.New()
h.Write([]byte(s))
bs := h.Sum(nil)
fmt.Println(s)
fmt.Printf("%x\n",bs)
}
结果如下:
i love cyj
93452691dfa19ac3c4d58f3672da75ebdf348dc3
package main
import "fmt"
import b64 "encoding/base64"
func main(){
//这是将要编解码的字符串。
data := "i love cyj"
//Go 同时支持标准的和 URL 兼容的 base64 格式。编码需要使用 []byte 类型的参数,所以要将字符串转成此类型。
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)
//解码可能会返回错误,如果不确定输入信息格式是否正确,那么,你就需要进行错误检查了。
sDec, _ := b64.StdEncoding.DecodeString(sEnc)
fmt.Println(string(sDec))
fmt.Println()
//使用 URL 兼容的 base64 格式进行编解码。
uEnc := b64.URLEncoding.EncodeToString([]byte(data))
fmt.Println(uEnc)
uDec, _ := b64.URLEncoding.DecodeString(uEnc)
fmt.Println(string(uDec))
}
结果如下:
aSBsb3ZlIGN5ag==
i love cyj
aSBsb3ZlIGN5ag==
i love cyj
- 读文件
代码如下:
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
)
func check(e error){
if e!=nil{
panic(e)
}
}
func main(){
//也许大部分基本的文件读取任务是将文件内容读取到内存中。
dat,err := ioutil.ReadFile("D:/GOPATH/src/awesomeProject/example/main/defer.txt")
check(err)
fmt.Println(string(dat))
//对于这个任务,从使用 os.Open打开一个文件获取一个 os.File 值开始。
f,err := os.Open("D:/GOPATH/src/awesomeProject/example/main/defer.txt")
check(err)
//从文件开始位置读取一些字节。这里最多读取 6 个字节,并且这也是我们实际读取的字节数。
b1 := make([]byte,6)
n1,err := f.Read(b1)
check(err)
fmt.Printf("%d bytes: %s \n",n1,string(b1))
//你也可以 Seek 到一个文件中已知的位置并从这个位置开始进行读取。
o2,err := f.Seek(7,0)
check(err)
b2 := make([]byte,3)
n2,err := f.Read(b2)
check(err)
fmt.Printf("%d bytes @ %d: %s\n",n2,o2,string(b2))
//io 包提供了一些可以帮助我们进行文件读取的函数。
o3,err := f.Seek(7,0)
check(err)
b3 := make([]byte,3)
n3,err := io.ReadAtLeast(f,b3,3)
check(err)
fmt.Printf("%d bytes @ %d: %s\n",n3,o3,string(b3))
//没有内置的回转支持,但是使用 Seek(0, 0) 实现。
_,err = f.Seek(0,0)
check(err)
//bufio 包实现了带缓冲的读取,这不仅对有很多小的读取操作的能提升性能,也提供了很多附加的读取函数。
r4 := bufio.NewReader(f)
b4,err := r4.Peek(10)
check(err)
fmt.Printf("10 bytes: %s\n",string(b4))
//任务结束后要关闭这个文件(通常这个操作应该在 Open操作后立即使用 defer 来完成)。
f.Close()
}
结果如下:
i love cyj
6 bytes: i love
3 bytes @ 7: cyj
3 bytes @ 7: cyj
10 bytes: i love cyj
- 写文件
代码如下:
package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
)
func check(e error){
if e!=nil{
panic(e)
}
}
func main(){
//开始,这里是展示如写入一个字符串(或者只是一些字节)到一个文件。
d1 := []byte("hello\nworld\n")
err := ioutil.WriteFile("D:/GOPATH/src/awesomeProject/example/main/defer.txt",d1,0644)
check(err)
//对于更细粒度的写入,先打开一个文件。
f,err := os.Create("D:/GOPATH/src/awesomeProject/example/main/dat.txt")
check(err)
//打开文件后,习惯立即使用 defer 调用文件的 Close操作。
defer f.Close()
//你可以写入你想写入的字节切片
d2 := []byte("i love cyj\n")
n2,err := f.Write(d2)
check(err)
fmt.Printf("write %d bytes\n",n2)
//WriteString 也是可用的。
n3,err := f.WriteString("cyj love me too\n")
check(err)
fmt.Printf("write %d bytes\n",n3)
//调用 Sync 来将缓冲区的信息写入磁盘。
f.Sync()
//bufio 提供了和我们前面看到的带缓冲的读取器一样的带缓冲的写入器。
w := bufio.NewWriter(f)
n4,err := w.WriteString("buffered\n")
check(err)
fmt.Printf("write %d bytes\n",n4)
//使用 Flush 来确保所有缓存的操作已写入底层写入器。
w.Flush()
}
结果如下:
write 11 bytes
write 16 bytes
write 9 bytes
- 行过滤器
代码如下:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main(){
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan(){
//Text 返回当前的 token,现在是输入的下一行。
ucl := strings.ToUpper(scanner.Text())
//写出大写的行。
fmt.Println(ucl)
}
//检查 Scan 的错误。文件结束符是可以接受的,并且不会被 Scan 当作一个错误。
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
}
结果如下:
hello
HELLO
world
WORLD
代码如下:
package main
import (
"fmt"
"os"
"strings"
)
func main() {
//使用 os.Setenv 来设置一个键值队。使用 os.Getenv获取一个键对应的值。如果键不存在,将会返回一个空字符串。
os.Setenv("FOO", "1")
fmt.Println("FOO:", os.Getenv("FOO"))
fmt.Println("BAR:", os.Getenv("BAR"))
//使用 os.Environ 来列出所有环境变量键值队。这个函数会返回一个 KEY=value 形式的字符串切片。
fmt.Println()
for _, e := range os.Environ() {
pair := strings.Split(e, "=")
fmt.Println(pair[0])
}
}
结果如下:
FOO: 1
BAR:
ALLUSERSPROFILE
APPDATA
CommonProgramFiles
CommonProgramFiles(x86)
CommonProgramW6432
COMPUTERNAME
ComSpec
configsetroot
FOO
FPS_BROWSER_APP_PROFILE_STRING
FPS_BROWSER_USER_PROFILE_STRING
GOPATH
GOROOT
HOMEDRIVE
HOMEPATH
LOCALAPPDATA
LOGONSERVER
NUMBER_OF_PROCESSORS
OneDrive
OS
Path
PATHEXT
PROCESSOR_ARCHITECTURE
PROCESSOR_IDENTIFIER
PROCESSOR_LEVEL
PROCESSOR_REVISION
ProgramData
ProgramFiles
ProgramFiles(x86)
ProgramW6432
PSModulePath
PUBLIC
SESSIONNAME
SystemDrive
SystemRoot
TEMP
TMP
USERDOMAIN
USERDOMAIN_ROAMINGPROFILE
USERNAME
USERPROFILE
windir
- 退出
代码如下:
package main
import (
"fmt"
"os"
)
func main() {
//当使用 os.Exit 时 defer 将不会 执行,所以这里的 fmt.Println将永远不会被调用。
defer fmt.Println("!")
//退出并且退出状态为 3。
os.Exit(3)
}
结果如下:
Process finished with exit code 3