项目地址:Go by Example
Hello World
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
Values
package main
import "fmt"
func main() {
fmt.Println("go" + "lang")
fmt.Println("1+1=", 1+1)
fmt.Println("7.0/3.0", 7.0/3.0)
fmt.Println(true && false)
}
fmt.Println() 函数是一个可变参数函数,可以接受任意数量的参数,并在输出时将它们格式化为字符串。在执行 fmt.Println("1+1=", 1+1) 时,Go 会将第一个参数 "1+1=" 和第二个参数 1+1格式化为字符串,并将它们连在一起输出。由于1+1 是一个表达式,它会在编译时求值并将结果转换为字符串。
Variables
package main
import "fmt"
func main() {
var a = "golang"
var b, c = 12, 34
var d = true
e := "ry4n"
fmt.Println(a, b, c, d, e)
}
Constants
package main
import (
"fmt"
"math")
const s string = "conststring"
func main() {
fmt.Println(s)
const n = 500
fmt.Println(n)
fmt.Println(int64(n))
fmt.Println(math.Sin(n))
}
数值型的常量在被赋予类型之前没有类型,例如显示转换。
For
package main
import "fmt"
func main() {
i := 1
for i < 5 {
fmt.Println(i)
i++
}
for j := 1; j < 3; j++ {
fmt.Println(j)
}
for k := 0; k < 5; k++ {
if k%2 == 0 {
continue
}
fmt.Println(k)
}
}
If/Else
package main
import (
"fmt"
)
func main() {
if 7%2 == 0 {
fmt.Println("even")
}
if 8%2 == 0 {
fmt.Println("odd")
}
if 7%2 == 0 && 8%2 == 0 {
fmt.Println(false)
}
if 7%2 == 0 || 8%2 == 0 {
fmt.Println(true)
}
}
Switch
package main
import "fmt"
func main() {
var input string
fmt.Scanln(&input)
switch input {
case "1":
{
fmt.Println("input 1")
}
case "2":
{
fmt.Println("input 2")
}
case "3":
{
fmt.Println("input 3")
}
default:
fmt.Println("input others")
}
}
Arrays
package main
import "fmt"
func main() {
var a [5]int
for i := range a {
fmt.Println(a[i])
}
a[1] = 3
fmt.Println(a[1])
fmt.Println(len(a))
}
Slice
package main
import (
"fmt"
"reflect")
func main() {
var s []string
fmt.Println(reflect.TypeOf(s))
fmt.Println(len(s), cap(s))
s1 := make([]string, 5)
fmt.Println(reflect.TypeOf(s1))
fmt.Println(len(s1), cap(s1))
s1[0] = "a"
s1 = append(s1, "b")
fmt.Println(s1)
fmt.Println(len(s1), cap(s1))
}
Map
package main
import "fmt"
func main() {
m := make(map[int]string)
m[1] = "first"
m[2] = "second"
fmt.Println(m)
delete(m, 1)
fmt.Println(m)
m = make(map[int]string)
fmt.Println(m)
}
可以通过 make 创建一个新的 map,来删除原来 map 中的数据。
Range
package main
import "fmt"
func main() {
num := []int{2, 3, 4}
sum := 0
for _, i := range num {
sum += i
}
fmt.Println(sum)
m := make(map[string]string)
m["a"] = "apple"
m["b"] = "golang"
for k, v := range m {
fmt.Println(k, v)
}
for j := range m {
fmt.Println(j)
}
}
Functions
package main
import "fmt"
func plus(a, b int) int {
return a + b
}
func main() {
res := plus(2, 3)
fmt.Println(res)
}
Multiple Return Values
package main
import "fmt"
func test() (int, int) {
return 1, 2
}
func main() {
a, b := test()
fmt.Println(a, b)
}
Variadic Functions
package main
import (
"fmt"
"reflect")
func sum(nums ...int) {
fmt.Println(nums, " ")
fmt.Println(reflect.TypeOf(nums))
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
sum(1, 2)
sum(1, 2, 3)
nums := []int{1, 2, 3, 4, 5}
sum(nums...)
}
Closures
package main
import "fmt"
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
func main() {
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
newInts := intSeq()
fmt.Println(newInts())
}
Recursion
package main
import "fmt"
func fact(n int) int {
if n == 0 {
return 1
}
return n * fact(n-1)
}
func main() {
fmt.Println(fact(5))
}
Pointers
package main
import "fmt"
func zeroval(ival int) {
ival = 0
}
func zeroptr(iptr *int) {
*iptr = 0
}
func main() {
i := 1
fmt.Println("initial:", i)
zeroval(i)
fmt.Println("zeroval:", i)
zeroptr(&i)
fmt.Println("zeroptr:", i)
fmt.Println("pointer:", &i)
}
Structs
package main
import "fmt"
type company struct {
name string
id int
}
func newCompany(name string) *company {
item := company{name: name}
return &item
}
func main() {
fmt.Println(company{"AAA", 20})
fmt.Println(newCompany("BBB"))
fmt.Println(&company{name: "Ann", id: 40})
fmt.Println(company{name: "Ann", id: 40})
}
Methods
package main
import "fmt"
type rect struct {
width int
height int
}
func (r *rect) area() int {
return r.width * r.height
}
func (r *rect) c() int {
return 2*r.width + 2*r.height
}
func main() {
re := rect{5, 3}
fmt.Println(re.area())
fmt.Println(re.c())
}
golang 也支持在 struct 上定义方法。
Struct Embedding
package main
import "fmt"
type base struct {
num int
}
type container struct {
base
str string
}
func main() {
c := container{base{
num: 1,
}, "test"}
fmt.Println(c.base, c.str, c.num, c.base.num)
}
Errors
package main
import (
"errors"
"fmt")
func f(arg int) (int, error) {
if arg == 42 {
return -1, errors.New("can't work with 42")
}
return arg + 3, nil
}
var ErrOutOfTea = fmt.Errorf("no more tea available")
var ErrPower = fmt.Errorf("can't boil water")
func makeTea(arg int) error {
if arg == 2 {
return ErrOutOfTea
} else if arg == 4 {
return fmt.Errorf("making tea: %w", ErrPower)
}
return nil
}
func main() {
err := makeTea(2)
fmt.Println(err)
_, err = f(42)
fmt.Println(err)
}
Goroutines
package main
import (
"fmt"
"time")
func a(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, " : ", i)
}
}
func main() {
a("direct")
go a("goroutine")
go func(msg string) {
fmt.Println(msg)
}("going")
time.Sleep(time.Second)
fmt.Println("done")
}
Channels
package main
import "fmt"
func main() {
messages := make(chan string)
go func() {
messages <- "ping"
}()
msg := <-messages
fmt.Println(msg)
}
Channel Buffering
package main
import "fmt"
func main() {
messages := make(chan string, 2)
messages <- "buffered"
messages <- "channel"
fmt.Println(<-messages)
fmt.Println(<-messages)
}
channel 默认是无缓冲的,因此需要有另一个 channel 接收。但是如果设置了有缓存的,则不需要。
Channel Synchronization
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, 1)
go worker(done)
<-done
}
代码中的 <-done 表示主程序从通道 done中接收数据。在该程序中,当 worker goroutine 完成其工作后,它会将一个布尔值发送到 done 通道,而主程序则等待从 done 通道接收数据。如果删除了<-done,主程序就不会等待worker goroutine完成其工作。虽然worker goroutine可能会成功地将一个布尔值发送到通道中(因为通道是有缓冲的,所以发送不会被阻塞),但是主程序不会等待这个值的接收,而是直接退出了。这样一来,即使 worker goroutine 已经完成了它的工作,主程序也提前退出了,整个程序也就结束了。
Channel Directions
package main
import "fmt"
func ping(pings chan<- string, msg string) {
pings <- msg
}
func pong(pings <-chan string, pongs chan<- string) {
msg := <-pings
pongs <- msg
}
func main() {
pings := make(chan string, 1)
pongs := make(chan string, 1)
ping(pings, "passed message")
pong(pings, pongs)
fmt.Println(<-pongs)
}
Select
在 Go 语言中,select 语句用于处理多个通道操作。它类似于 switch 语句,但用于通道操作。select 语句使得一个 Go 程序可以等待多个通道操作同时响应。
-
多通道操作:select 语句允许在多个通道上等待操作,一次只处理一个准备好的通道操作。
-
随机选择:如果多个 case 同时准备好,select 会随机选择其中一个来执行。
-
无阻塞等待:如果没有任何通道准备好,select 会立即执行 default 语句(如果存在)。这种特性使得 select 语句可以用于非阻塞的通道操作。
-
阻塞等待:如果没有 default 语句,并且所有 case 都没有准备好,select 语句会阻塞,直到其中一个 case 准备好。
package main
import (
"fmt"
"time")
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(time.Second * 2)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
Timeouts
package main
import (
"fmt"
"time")
func main() {
c1 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c1 <- "result 1"
}()
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(1 * time.Second):
fmt.Println("timeout 1")
}
c2 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c2 <- "result 2"
}()
select {
case res := <-c2:
fmt.Println(res)
case <-time.After(3 * time.Second):
fmt.Println("timeout 2")
}
}
Non-Blocking Channel Operations
package main
import "fmt"
func main() {
messages := make(chan string)
signals := make(chan bool)
select {
case msg := <-messages:
fmt.Println("received messages", msg)
default:
fmt.Println("no messages received")
}
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message sent")
}
select {
case msg := <-messages:
fmt.Println("received messages", msg)
case sig := <-signals:
fmt.Println("received signal", sig)
default:
fmt.Println("no activity")
}
}
这里的通道是无缓存的,因此 msg 无法发送到通道中,阻塞。
Closing Channels
package main
import "fmt"
func main() {
jobs := make(chan int, 5)
done := make(chan bool)
go func() {
for {
j, more := <-jobs
if more {
fmt.Println("received job", j)
} else {
fmt.Println("received all jobs")
done <- true
return
}
}
}()
for j := 1; j <= 3; j++ {
jobs <- j
fmt.Println("sent job", j)
}
close(jobs)
fmt.Println("sent all jobs")
<-done
_, ok := <-jobs
fmt.Println("received more jobs:", ok)
}
这段代码运行结果为:
sent job 1
sent job 2
sent job 3
sent all jobs
received job 1
received job 2
received job 3
received all jobs
received more jobs: false
首先,在主线程中,进入循环,每次打印出 sent job,3 次之后,关闭 jobs 通道,并且打印 sent all jobs,此时,<-done 的作用是阻塞主线程,等待从 done 中接收一个值,在此期间 goroutine 接收到 jobs 的消息,并且打印出 received jobs,3 次之后,received all jobs,并且给 done 复制,此时阻塞继续执行,由于 jobs 已经关闭,因此 ok 为 false,打印 received more jobs: false。
Range over Channels
package main
import "fmt"
func main() {
queue := make(chan string, 2)
queue <- "one"
queue <- "two"
close(queue)
for i := range queue {
fmt.Println(i)
}
}
Timers
package main
import (
"fmt"
"time")
func main() {
time1 := time.NewTimer(time.Second * 2)
<-time1.C
fmt.Println("Timer 1 fired")
timer2 := time.NewTimer(time.Second)
go func() {
<-timer2.C
fmt.Println("Timer 2 fired")
}()
stop2 := timer2.Stop()
if stop2 {
fmt.Println("Timer 2 stopped")
}
time.Sleep(time.Second * 2)
}
Tickers
package main
import (
"fmt"
"time")
func main() {
ticker := time.NewTicker(500 * time.Millisecond)
done := make(chan bool)
go func() {
for {
select {
case <-done:
return
case t := <-ticker.C:
fmt.Println("Tick at", t)
}
}
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()
done <- true
fmt.Println("Ticker Stopped")
}
与 Timer 的区别在于,tickers are for when you want to do something repeatly
Worker Pools
package main
import (
"fmt"
"time")
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "started job", j)
time.Sleep(time.Second)
fmt.Println("worker", id, "finished job", j)
results <- j * 2
}
}
func main() {
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
for a := 1; a <= numJobs; a++ {
<-results
}
}
jobs <-chan int, results chan<- int 分别为一个只读和只写的通道,虽然只启动了 3 个 worker 协程,但是向 jobs 通道发送了 5 个任务。这些任务会被这 3 个 worker 协程并发地处理。
WaitGroups
package main
import (
"fmt"
"sync" "time")
func worker(id int) {
fmt.Println("worker starting ", id)
time.Sleep(time.Second)
fmt.Println("worker done ", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
worker(i)
}()
}
wg.Wait()
}
使用 waitgroups 来等待所有 goroutines 完成。
Rate Limiting
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(200 * time.Millisecond)
for req := range requests {
<-limiter
fmt.Println("request", req, time.Now())
}
}
如果想限制速率,可以通过 time.Tick 设置一个 limiter。
Atomic Counters
package main
import (
"fmt"
"sync" "sync/atomic")
func main() {
var ops atomic.Uint64
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
for c := 0; c < 1000; c++ {
ops.Add(1)
}
wg.Done()
}()
}
wg.Wait()
fmt.Println("ops:", ops.Load())
}
使用 load 来更新,线程安全。
Mutexes
package main
import (
"fmt"
"sync")
type Container struct {
mu sync.Mutex
counters map[string]int
}
func (c *Container) inc(name string) {
c.mu.Lock()
defer c.mu.Unlock()
c.counters[name]++
}
func main() {
c := Container{
counters: map[string]int{"a": 0, "b": 0},
}
var wg sync.WaitGroup
doIncrement := func(name string, n int) {
for i := 0; i < n; i++ {
c.inc(name)
}
wg.Done()
}
wg.Add(3)
go doIncrement("a", 10000)
go doIncrement("a", 10000)
go doIncrement("b", 10000)
wg.Wait()
fmt.Println(c.counters)
}
对于更复杂的场景,想要在多线程中安全地操作数据,可以利用 mutex。在获取数据之前,先用 mutex 锁住,再通过 defer 进行 unlock。
Panic
package main
import "os"
func main() {
panic(" a problem")
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}
Recover
package main
import "fmt"
func myPanic() {
panic("a problem")
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("revocered. Error ", r)
}
}()
myPanic()
fmt.Println("After mypanic()")
}
Go 可以通过 recover 函数从 panic 中恢复,可以阻止 panic 中止程序,让它继续执行。例如下面的场景:如果其中一个客户端连接出现严重错误,服务器不希望崩溃。而是希望关闭该连接并继续为其他客户端提供服务。recover 必须在 defer 函数中调用。
Text Templates
package main
import (
"os"
"text/template")
func main() {
t1 := template.New("t1")
t1, err := t1.Parse("Value is {{.}}n")
if err != nil {
panic(err)
}
t1 = template.Must(t1.Parse("Value: {{.}}n"))
t1.Execute(os.Stdout, "some text")
t1.Execute(os.Stdout, 5)
t1.Execute(os.Stdout, []string{
"Go",
"Rust",
"C++",
"C#",
})
Create := func(name, t string) *template.Template {
return template.Must(template.New(name).Parse(t))
}
t2 := Create("t2", "Name: {{.Name}}n")
t2.Execute(os.Stdout, struct {
Name string
}{"Jane Doe"})
t2.Execute(os.Stdout, map[string]string{
"Name": "Mickey Mouse",
})
t3 := Create("t3",
"{{if . -}} yes {{else -}} no {{end}}n")
t3.Execute(os.Stdout, "not empty")
t3.Execute(os.Stdout, "")
t4 := Create("t4",
"Range: {{range .}}{{.}} {{end}}n")
t4.Execute(os.Stdout,
[]string{
"Go",
"Rust",
"C++",
"C#",
})
}
展示动态内容或自定义输入。
Regular Expressions
package main
import (
"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"))
fmt.Println(r.FindStringIndex("peach punch"))
fmt.Println(r.FindStringSubmatch("peach punch"))
fmt.Println(r.FindStringSubmatchIndex("peach punch"))
fmt.Println(r.FindAllString("peach punch pinch", -1))
fmt.Println(r.FindAllString("peach punch pinch", 0))
fmt.Println(r.FindAllString("peach punch pinch", 1))
fmt.Println(r.FindAllString("peach punch pinch", 2))
}
使用正则表达式创建全局变量时,最好用 MustCompile ,因为 MustCompile 会返回 panic 而不是返回错误,这使得用于全局变量更安全。
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() {
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))
res1D := &response1{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res1B, _ := json.Marshal(res1D)
fmt.Println(string(res1B))
res2D := &response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
var dat map[string]interface{}
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
num := dat["num"].(float64)
fmt.Println(num)
strs := dat["strs"].([]interface{})
str1 := strs[0].(string)
fmt.Println(str1)
str := `{"page": 1, "fruits": ["apple", "peach"]}`
res := response2{}
json.Unmarshal([]byte(str), &res)
fmt.Println(res)
fmt.Println(res.Fruits[0])
enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple": 5, "lettuce": 7}
enc.Encode(d)
}
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.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())
p(then.Weekday())
p(then.Before(now))
p(then.After(now))
p(then.Equal(now))
diff := now.Sub(then)
p(diff)
p(diff.Hours())
p(diff.Minutes())
p(diff.Seconds())
p(diff.Nanoseconds())
p(then.Add(diff))
p(then.Add(-diff))
}
Random Numbers
package main
import (
"fmt"
"math/rand")
func main() {
fmt.Print(rand.Int(), ",")
fmt.Print(rand.Int())
fmt.Println()
fmt.Println(rand.Float64())
fmt.Print((rand.Float64()*5)+5, ",")
fmt.Print((rand.Float64() * 5) + 5)
fmt.Println()
}
Number Parsing
package main
import (
"fmt"
"strconv")
func main() {
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f)
i, _ := strconv.ParseInt("123", 0, 64)
fmt.Println(i)
d, _ := strconv.ParseInt("0x1c8", 0, 64)
fmt.Println(d)
u, _ := strconv.ParseUint("789", 0, 64)
fmt.Println(u)
k, _ := strconv.Atoi("135")
fmt.Printf("%Tn", k)
fmt.Println(k)
_, e := strconv.Atoi("wat")
fmt.Println(e)
}
URL Parsing
package main
import (
"fmt"
"net" "net/url")
func main() {
s := "postgres://user:[email protected]:5432/path?k=v#f"
u, err := url.Parse(s)
if err != nil {
panic(err)
}
fmt.Println(u.Scheme)
fmt.Println(u.User)
fmt.Println(u.User.Username())
p, _ := u.User.Password()
fmt.Println(p)
fmt.Println(u.Host)
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])
}
SHA256 Hashes
package main
import (
"crypto/sha256"
"fmt")
func main() {
s := "sha256 this string"
h := sha256.New()
h.Write([]byte(s))
bs := h.Sum(nil)
fmt.Printf("%x", bs)
}
Base64 Encoding
package main
import (
b64 "encoding/base64"
"fmt")
func main() {
data := "abc123!?$*&()'-=@~"
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)
sDec, _ := b64.StdEncoding.DecodeString(sEnc)
fmt.Println(string(sDec))
fmt.Println()
uEnc := b64.URLEncoding.EncodeToString([]byte(data))
fmt.Println(uEnc)
uDec, _ := b64.URLEncoding.DecodeString(uEnc)
fmt.Println(string(uDec))
}
Reading Files
package main
import (
"fmt"
"os")
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
data, err := os.ReadFile("testfile")
check(err)
fmt.Print(string(data))
}
Writing Files
package main
import (
"fmt"
"os")
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
d1 := []byte("hellongon")
err := os.WriteFile("writefile", d1, 0644)
check(err)
f, err := os.Create("writefile2")
check(err)
defer f.Close()
d2 := []byte{115, 111, 109, 101, 10}
n2, err := f.Write(d2)
check(err)
fmt.Println("write bytes: ", n2)
n3, err := f.WriteString("writesn")
check(err)
fmt.Println("write bytes: ", n3)
f.Sync()
}
Line Filters
package main
import (
"bufio"
"fmt" "os" "strings")
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
ucl := strings.ToUpper(scanner.Text())
fmt.Println(ucl)
}
if err := scanner.Err(); err != nil {
fmt.Println(os.Stderr, "error: ", err)
os.Exit(1)
}
}
File Paths
package main
import (
"fmt"
"path/filepath" "strings")
func main() {
p := filepath.Join("dir1", "dir2", "filename")
fmt.Println("p:", p)
fmt.Println(filepath.Join("dir1//", "filename"))
fmt.Println(filepath.Join("dir1/../dir1", "filename"))
fmt.Println("Dir(p):", filepath.Dir(p))
fmt.Println("Base(p):", filepath.Base(p))
fmt.Println(filepath.IsAbs("dir/file"))
fmt.Println(filepath.IsAbs("C:/a/dir/file"))
filename := "config.json"
fmt.Println(filepath.Ext(filename))
fmt.Println(strings.TrimSuffix(filename, filepath.Ext(filename)))
}
filepath.Join 会自动删除多余的分隔符等等来进行归一化。
Directories
package main
import (
"fmt"
"io/fs" "os" "path/filepath")
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
err := os.Mkdir("subdir", 0755)
check(err)
defer os.RemoveAll("subdir")
createEmptyFile := func(name string) {
d := []byte("")
check(os.WriteFile(name, d, 0644))
}
createEmptyFile("subdir/file1")
err = os.MkdirAll("subdir/parent/child", 0755)
check(err)
createEmptyFile("subdir/parent/file2")
createEmptyFile("subdir/parent/file3")
createEmptyFile("subdir/parent/child/file4")
c, err := os.ReadDir("subdir/parent")
check(err)
fmt.Println("Listing subdir/parent")
for _, entry := range c {
fmt.Println(" ", entry.Name(), entry.IsDir())
}
err = os.Chdir("subdir/parent/child")
check(err)
c, err = os.ReadDir(".")
check(err)
fmt.Println("Listing subdir/parent/child")
for _, entry := range c {
fmt.Println(" ", entry.Name(), entry.IsDir())
}
err = os.Chdir("../../..")
check(err)
fmt.Println("Visiting subdir")
err = filepath.WalkDir("subdir", visit)
}
func visit(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
fmt.Println(" ", path, d.IsDir())
return nil
}
os.RemoveAll-->rm -rfos.MkdirAll-->mkdir -pos.Chdir-->cd
Temporary Files and Directories
package main
import (
"fmt"
"os" "path/filepath")
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
f, err := os.CreateTemp("", "sample")
check(err)
fmt.Println("Temp file name:", f.Name())
defer os.Remove(f.Name())
_, err = f.Write([]byte("testfile"))
check(err)
dname, err := os.MkdirTemp("", "sampledir")
check(err)
fmt.Println("Temp dir name:", dname)
defer os.RemoveAll(dname)
fname := filepath.Join(dname, "file1")
fmt.Println(fname)
err = os.WriteFile(fname, []byte{1, 2}, 0644)
check(err)
}
通过 os.CreateTemp 在操作系统默认位置创建临时文件。
Command-Line Arguments
package main
import (
"fmt"
"os")
func main() {
argswithprog := os.Args
argswithoutprog := os.Args[1:]
arg := os.Args[3]
fmt.Println(argswithprog)
fmt.Println(argswithoutprog)
fmt.Println(arg)
}
Command-Line Flags
package main
import (
"flag"
"fmt")
func main() {
wordPtr := flag.String("word", "foo", "a string")
numPtr := flag.Int("num", 42, "an int")
forkPtr := flag.Bool("fork", false, "a bool")
var svar string
flag.StringVar(&svar, "svar", "bar", "a string var")
flag.Parse()
fmt.Println("word:", *wordPtr)
fmt.Println("numb:", *numPtr)
fmt.Println("fork:", *forkPtr)
fmt.Println("svar:", svar)
fmt.Println("tail:", flag.Args())
}
执行结果如下:
PS C:UsersRy4nDesktopgolanggobyexample> .CmdFlags.exe
word: foo
numb: 42
fork: false
svar: bar
tail: []
PS C:UsersRy4nDesktopgolanggobyexample> .CmdFlags.exe -word abc
word: abc
numb: 42
fork: false
svar: bar
tail: []
PS C:UsersRy4nDesktopgolanggobyexample> .CmdFlags.exe -word abc -fork
word: abc
numb: 42
fork: true
svar: bar
tail: []
另外,-h 会获取自动生成的帮助文本内容
Command-Line Subcommands
package main
import (
"flag"
"fmt" "os")
func main() {
fooCmd := flag.NewFlagSet("foo", flag.ExitOnError)
fooEnable := fooCmd.Bool("enable", false, "enable")
fooName := fooCmd.String("name", "", "name")
barCmd := flag.NewFlagSet("bar", flag.ExitOnError)
barLevel := barCmd.Int("level", 0, "level")
if len(os.Args) < 2 {
fmt.Println("expect 'foo' or 'bar' subcommands")
os.Exit(1)
}
switch os.Args[1] {
case "foo":
fooCmd.Parse(os.Args[2:])
fmt.Println("subcommand 'foo'")
fmt.Println(" enable:", *fooEnable)
fmt.Println(" name:", *fooName)
fmt.Println(" tail:", fooCmd.Args())
case "bar":
barCmd.Parse(os.Args[2:])
fmt.Println("subcommand 'bar'")
fmt.Println(" level:", *barLevel)
fmt.Println(" tail:", barCmd.Args())
default:
fmt.Println("expected 'foo' or 'bar' subcommands")
os.Exit(1)
}
}
Environment Variables
package main
import (
"fmt"
"os" "strings")
func main() {
os.Setenv("FOO", "1")
fmt.Println("FOO:", os.Getenv("FOO"))
fmt.Println("WQW:", os.Getenv("WQW"))
fmt.Println()
for _, e := range os.Environ() {
pair := strings.SplitN(e, "=", 2)
fmt.Println(pair[0], " ", pair[1])
}
}
Logging
package main
import (
"bytes"
"fmt" "log" "os")
func main() {
log.Println("standard logger")
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
log.Println("with micro")
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Println("with file/line")
mylog := log.New(os.Stdout, "my:", log.LstdFlags)
mylog.Println("from mylog")
mylog.SetPrefix("ohmy:")
mylog.Println("from mylog")
var buf bytes.Buffer
buflog := log.New(&buf, "buf:", log.LstdFlags)
buflog.Println("hello")
fmt.Print("from buflog:", buf.String())
}
HTTP Client
package main
import (
"bufio"
"fmt" "net/http")
func main() {
resp, err := http.Get("https://gobyexample.com")
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("status code", resp.Status)
scanner := bufio.NewScanner(resp.Body)
for i := 0; scanner.Scan() && i < 5; i++ {
fmt.Println(scanner.Text())
}
}
HTTP Server
package main
import (
"fmt"
"net/http")
func hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "htllon")
}
func headers(w http.ResponseWriter, req *http.Request) {
for name, headers := range req.Header {
for _, h := range headers {
fmt.Fprintf(w, "%v:%vn", name, h)
}
}
}
func main() {
http.HandleFunc("/hello", hello)
http.HandleFunc("/headers", headers)
http.ListenAndServe(":8090", nil)
}
Spawning Processes
package main
import (
"fmt"
"io" "os/exec")
func main() {
dateCmd := exec.Command("date")
dateOut, err := dateCmd.Output()
if err != nil {
panic(err)
}
fmt.Println("> date")
fmt.Println(string(dateOut))
_, err = exec.Command("date", "-x").Output()
if err != nil {
switch e := err.(type) {
case *exec.Error:
fmt.Println("failed executing:", err)
case *exec.ExitError:
fmt.Println("command exit rc =", e.ExitCode())
default:
panic(err)
}
}
grepCmd := exec.Command("grep", "hello")
grepIn, _ := grepCmd.StdinPipe()
grepOut, _ := grepCmd.StdoutPipe()
grepCmd.Start()
grepIn.Write([]byte("hello grepngoodbye grep"))
grepIn.Close()
grepBytes, _ := io.ReadAll(grepOut)
grepCmd.Wait()
fmt.Println("> grep hello")
fmt.Println(string(grepBytes))
lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
lsOut, err := lsCmd.Output()
if err != nil {
panic(err)
}
fmt.Println("> ls -a -l -h")
fmt.Println(string(lsOut))
}
Exec'ing Processes
package main
import (
"os"
"os/exec" "syscall")
func main() {
binary, lookErr := exec.LookPath("ls")
if lookErr != nil {
panic(lookErr)
}
args := []string{"ls", "-a", "-l", "-h"}
env := os.Environ()
execErr := syscall.Exec(binary, args, env)
if execErr != nil {
panic(execErr)
}
}
spawning external processes:需要一个外部进程来运行 goexec process:需要另一个进程来替换当前的 go 进程
Exit
package main
import (
"fmt"
"os"
)
func main() {
defer fmt.Println("!")
os.Exit(3)
}
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论