跟着实例学Go语言(三)

不会ps,你也可以成为ps高手,最强傻瓜式人像一键磨皮美白瘦脸美妆PS插件 比如:美肤是用来去斑点的,如果效果不太理想,就加大百分比,反之就减小。瘦脸如果脸胖的就打开,正常的就关闭。所谓的一键调节,要不只能调节一种效果,要不就是个预设,然后让你自己再调。同时,该软件还加入了贴心的批量处理功能,能同时处理上千张照片,让您喝着茶也能将工作做完。、自动检测照片中的人脸,包括鼻子,嘴巴,耳朵,眼睛和眉毛。、依托强大的脸部识别功能,可以高效的对人物全身皮肤进行智能识别,处理,使肤质平滑、过渡均匀。,这是网上下载的模糊照片,经过简单处理,你可以发现,眼睛变的更亮,皮肤更白,眼袋消失。 阅读详情

本教程全面涵盖了Go语言基础的各个方面。一共80个例子,每个例子对应一个语言特性点,既适合新人快速上手,也适合工作中遇到问题速查知识点。
教程代码示例来自go by example,文字部分来自本人自己的理解。

本文是教程系列的第三部分,共计20个例子、约1.5万字。

系列文章快速跳转:
跟着实例学Go语言(一)
跟着实例学Go语言(二)
跟着实例学Go语言(三)
跟着实例学Go语言(四)

41. Mutexes

Go中处理同步的另一方式是使用互斥锁,这也是许多其他语言会采用的方式,保证加锁的代码块为原子操作。

package main

import (
    "fmt"
    "sync"
)

// 封装结构,包括:互斥锁和它保护的map计数器
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)
}
$ go run mutexes.go
map[a:20000 b:10000]

42. Stateful Goroutines

比起互斥锁,Go更推荐使用通道通信的方式来实现goroutine之间的同步。以下是一个使用channel通信来实现并发安全的缓存服务的例子。缓存服务从reads和writes两个channel中读取读写命令,并依次执行,从而避免了多个goroutine对缓存数据的竞争。两个channel在这里起到了消息队列的作用。

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 readOps uint64
    var writeOps uint64

    reads := make(chan readOp)
    writes := make(chan writeOp)

    go func() {
        var state = make(map[int]int)
        for {
        	//  缓存服务从两个channel取命令,串行执行,每次一条
            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{
                    key:  rand.Intn(5),
                    resp: make(chan int)}
                reads <- read
                <-read.resp
                // 接收到返回后将计数加1
                atomic.AddUint64(&readOps, 1)
                time.Sleep(time.Millisecond)
            }
        }()
    }

    for w := 0; w < 10; w++ {
        go func() {
            for {
                write := writeOp{
                    key:  rand.Intn(5),
                    val:  rand.Intn(100),
                    resp: make(chan bool)}
                writes <- write
                <-write.resp
                atomic.AddUint64(&writeOps, 1)
                time.Sleep(time.Millisecond)
            }
        }()
    }

    time.Sleep(time.Second)
	// 用LoadUint64保证读取计数为原子操作
    readOpsFinal := atomic.LoadUint64(&readOps)
    fmt.Println("readOps:", readOpsFinal)
    writeOpsFinal := atomic.LoadUint64(&writeOps)
    fmt.Println("writeOps:", writeOpsFinal)
}
$ go run stateful-goroutines.go
readOps: 71708
writeOps: 7177

43. Sorting

Go内置的排序函数支持对不同数据类型slice的排序。

package main

import (
    "fmt"
    "sort"
)

func main() {

	// 排序string和int要用不同的函数
    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)
}
$ go run sorting.go
Strings: [a b c]
Ints:    [2 4 7]
Sorted:  true

44. Sorting by Functions

除了按自然序排序,我们也可以通过函数自定义排序规则,对任意类型的结构体进行排序。下面例子是自定义byLength类型的结构体,然后对其中的string按长度进行排序。

package main

import (
    "fmt"
    "sort"
)

// 新类型是string slice的别名
type byLength []string

// 实现了排序所需的三个方法:Len、Swap、Less
// byLength实际就是string slice,是引用类型,因此不用传指针
func (s byLength) Len() int {
    return len(s)
}
func (s byLength) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}
func (s byLength) Less(i, j int) bool {
    return len(s[i]) < len(s[j])
}

func main() {
    fruits := []string{"peach", "banana", "kiwi"}
    // byLength实现排序接口后,可执行被Sort调用
    sort.Sort(byLength(fruits))
    fmt.Println(fruits)
}
$ go run sorting-by-functions.go 
[kiwi peach banana]

45. Panic

panic用于表示预期外的严重错误,遇到这种错误时应该第一时间失败,中止程序运行。对于一般的错误处理,Go推荐尽量使用error而非panic。

package main

import "os"

func main() {

    panic("a problem")

    _, err := os.Create("/tmp/file")
    if err != nil {
    	// 当遇到error不知道怎么处理时,可以包装成panic
        panic(err)
    }
}
$ go run panic.go
panic: a problem

	
// 程序会panic的那行直接退出,退出码不再是0
goroutine 1 [running]:
main.main()
    /.../panic.go:12 +0x47
...
exit status 2

46. Defer

defer用于将某段代码推迟到当前函数的最后执行,一般用于清理操作。它类似于Java中的finally,但不同的是,遇到panic后不保证defer的语句一定能执行,除非使用后面讲到的recover恢复。

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)
        os.Exit(1)
    }
}
$ go run defer.go
creating
writing
closing

47. Recover

Go提供了从panic中恢复的机制。类似于Java中的catch exception,可定义恢复后执行的操作。恢复通过recover函数实现,recover必须在defer函数中调用,在panic后会自动激活。可用这种方式确保defer函数一定得到执行。

package main

import "fmt"

func mayPanic() {
    panic("a problem")
}

func main() {

    defer func() {
    	// recover必须在defer函数中调用
        if r := recover(); r != nil {

            fmt.Println("Recovered. Error:\n", r)
        }
    }()

    mayPanic()

    fmt.Println("After mayPanic()")
}
$ go run recover.go
Recovered. Error:
 a problem

48. String Functions

Go内置的strings包提供了很多有用的string处理函数,如Contains(是否包含)、Join(连接)、Split(切分),具体参见如下示例。

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"))
}
$ go run string-functions.go
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

49. String Formatting

Go通过Printf提供了方便的格式化功能,例如%v(结构的值)、%d(数字)、%s(字符串),具体参见如下示例。

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")
}
$ go run string-formatting.go
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: 0xc0000ba000
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

50. Text Templates

Go提供了使用模板动态生成字符串或者HTML的功能。基于给定的模板,提供参数动态替换其中的占位符,可以有助于高效生成我们想要的文字。

package main

import (
    "os"
    "text/template"
)

func main() {

    t1 := template.New("t1")
    t1, err := t1.Parse("Value is {{.}}\n")
    if err != nil {
        panic(err)
    }

	// Must是上面包装err成panic的简便写法
    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#",
        })
}
$ go run templates.go 
Value: some text
Value: 5
Value: [Go Rust C++ C#]
Name: Jane Doe
Name: Mickey Mouse
yes 
no 
Range: Go Rust C++ C# 

51. Regular Expressions

像许多其他语言一样,Go也对正则表达式这一通用功能有良好支持。

package main

import (
    "bytes"
    "fmt"
    "regexp"
)

func main() {
	// 直接判断正则表达式和文字是否匹配
    match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
    fmt.Println(match)
	// 解析正则表达式。注意对于特殊符号,无需像Java一样用反斜杠转义
    r, _ := regexp.Compile("p([a-z]+)ch")
	// 再用解析好的正则,判断文字是否匹配
    fmt.Println(r.MatchString("peach"))

    fmt.Println(r.FindString("peach punch"))

    fmt.Println("idx:", 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("all:", r.FindAllStringSubmatchIndex(
        "peach punch pinch", -1))

    fmt.Println(r.FindAllString("peach punch pinch", 2))

    fmt.Println(r.Match([]byte("peach")))
	// 强制解析正则,失败则会panic
    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))
}
$ go run regular-expressions.go
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

52. JSON

Go语言对JSON提供了内置的支持,包括Marshal(编码)、Unmarshal(解码)。

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")
    fmt.Println(string(strB))

    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)
}
$ go run json.go
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[num:6.13 strs:[a b]]
6.13
a
{1 [apple peach]}
apple
{"apple":5,"lettuce":7}

53. XML

Go语言对XML提供了内置的支持,包括Marshal(编码)、Unmarshal(解码)。

package main

import (
    "encoding/xml"
    "fmt"
)

type Plant struct {
    XMLName xml.Name `xml:"plant"`
    Id      int      `xml:"id,attr"`
    Name    string   `xml:"name"`
    Origin  []string `xml:"origin"`
}

func (p Plant) String() string {
    return fmt.Sprintf("Plant id=%v, name=%v, origin=%v",
        p.Id, p.Name, p.Origin)
}

func main() {
    coffee := &Plant{Id: 27, Name: "Coffee"}
    coffee.Origin = []string{"Ethiopia", "Brazil"}

    out, _ := xml.MarshalIndent(coffee, " ", "  ")
    fmt.Println(string(out))

    fmt.Println(xml.Header + string(out))

    var p Plant
    if err := xml.Unmarshal(out, &p); err != nil {
        panic(err)
    }
    fmt.Println(p)

    tomato := &Plant{Id: 81, Name: "Tomato"}
    tomato.Origin = []string{"Mexico", "California"}

    type Nesting struct {
        XMLName xml.Name `xml:"nesting"`
        Plants  []*Plant `xml:"parent>child>plant"`
    }

    nesting := &Nesting{}
    nesting.Plants = []*Plant{coffee, tomato}

    out, _ = xml.MarshalIndent(nesting, " ", "  ")
    fmt.Println(string(out))
}
$ go run xml.go
 <plant id="27">
   <name>Coffee</name>
   <origin>Ethiopia</origin>
   <origin>Brazil</origin>
 </plant>
<?xml version="1.0" encoding="UTF-8"?>
 <plant id="27">
   <name>Coffee</name>
   <origin>Ethiopia</origin>
   <origin>Brazil</origin>
 </plant>
Plant id=27, name=Coffee, origin=[Ethiopia Brazil]
 <nesting>
   <parent>
     <child>
       <plant id="27">
         <name>Coffee</name>
         <origin>Ethiopia</origin>
         <origin>Brazil</origin>
       </plant>
       <plant id="81">
         <name>Tomato</name>
         <origin>Mexico</origin>
         <origin>California</origin>
       </plant>
     </child>
   </parent>
 </nesting>

54. Time

下面例子展示了Go的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))

	// 注意:两个时间计算差值,返回的是duration
    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))
}
$ go run time.go
2012-10-31 15:50:13.793654 +0000 UTC
2009-11-17 20:34:58.651387237 +0000 UTC
2009
November
17
20
34
58
651387237
UTC
Tuesday
true
false
false
25891h15m15.142266763s
25891.25420618521
1.5534752523711128e+06
9.320851514226677e+07
93208515142266763
2012-10-31 15:50:13.793654 +0000 UTC
2006-12-05 01:19:43.509120474 +0000 UTC

55. Epoch

Go也提供了基于时间得到时间戳,即从1970-1-1 0点到指定时间经历的秒、毫秒、纳秒数。

package main

import (
    "fmt"
    "time"
)

func main() {

    now := time.Now()
    fmt.Println(now)

	// 将时间转成基于秒、毫秒、纳秒的时间戳
    fmt.Println(now.Unix())
    fmt.Println(now.UnixMilli())
    fmt.Println(now.UnixNano())
	// 可以从时间戳反转成时间
    fmt.Println(time.Unix(now.Unix(), 0))
    fmt.Println(time.Unix(0, now.UnixNano()))
}
$ go run epoch.go 
2012-10-31 16:13:58.292387 +0000 UTC
1351700038
1351700038292
1351700038292387000
2012-10-31 16:13:58 +0000 UTC
2012-10-31 16:13:58.292387 +0000 UTC

56. Time Formatting / Parsing

下面例子展示了日期格式化和解析的方法。

package main

import (
    "fmt"
    "time"
)

func main() {
    p := fmt.Println
	// 使用RFC3339标准格式化
    t := time.Now()
    p(t.Format(time.RFC3339))
	// 使用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)
}
$ go run time-formatting-parsing.go 
2014-04-15T18:00:15-07:00
2012-11-01 22:08:41 +0000 +0000
6:00PM
Tue Apr 15 18:00:15 2014
2014-04-15T18:00:15.161182-07:00
0000-01-01 20:41:00 +0000 UTC
2014-04-15T18:00:15-00:00
parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": ...

57. Random Numbers

下面的例子展示了随机数的使用。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
	// 随机生成[0, 100)范围内的整数
    fmt.Print(rand.Intn(100), ",")
    fmt.Print(rand.Intn(100))
    fmt.Println()
	// 随机生成[0, 1)范围内的float64小数
    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))
}
$ go run random-numbers.go
81,87
0.6645600532184904
7.123187485356329,8.434115364335547
0,28
5,87
5,87

58. Number Parsing

下面例子展示了如何从string解析出数字。

package main

import (
    "fmt"
    "strconv"
)

func main() {
	// 解析64位精度的float
    f, _ := strconv.ParseFloat("1.234", 64)
    fmt.Println(f)
	// 解析64位整数,0代表从string自动推断数字的进制,此处为10进制
    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)
	// Atoi是解析10进制整数的简便写法
    k, _ := strconv.Atoi("135")
    fmt.Println(k)

    _, e := strconv.Atoi("wat")
    fmt.Println(e)
}
$ go run number-parsing.go 
1.234
123
456
789
135
strconv.ParseInt: parsing "wat": invalid syntax

59. URL Parsing

下面例子展示了从一个URL解析出用户名、密码、端口、文件路径等信息的方法。

package main

import (
    "fmt"
    "net"
    "net/url"
)

func main() {

    s := "postgres://user:pass@host.com: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])
}
$ go run url-parsing.go 
postgres
user:pass
user
pass
host.com:5432
host.com
5432
/path
f
k=v
map[k:[v]]
v

60. SHA256 Hashes

SHA256哈希经常被用来对文件或文字做签名。例如TLS/SSL就使用它计算证书签名。

package main

import (
    "crypto/sha256"
    "fmt"
)

func main() {
    s := "sha256 this string"

    h := sha256.New()

    h.Write([]byte(s))

	// 计算SHA256哈希
    bs := h.Sum(nil)

    fmt.Println(s)
    fmt.Printf("%x\n", bs)
}
$ go run sha256-hashes.go
sha256 this string
1af1dfa857bf1d8814fe1af8983c18080019922e557f15a8a...
【图像拼接】论文精读:As-Rigid-As-Possible Shape Manipulation(ARAP) 文章目录前言1.摘要2.算法的总体流程总结 前言 图像变形算法 1.摘要 论文提出了一个二维图形互动系统。图形是建立在三角形网格上的,用户只需移动几个网格顶点(限制顶点),系统通过最小化每个三角形的误差计算网格剩余顶点(自由顶点)的位置。 算法分两步: 适当旋转每个三角形。 调整大小。 关键是使用二次度量误差将最小化问题转换成线性方程组,然后再解这个方程组。 刚性形状变形是很难的,论文的研究使其变得简单。 2.算法的总体流程 总的流程分三步: 将图形用三角形网格覆盖 选择三个点(限制顶点) 操纵限 阅读详情

相关推荐

国产FPGA开发实战:紫光同创编程软件中的约束文件详解与常见问题

本文详细解析了紫光同创FPGA编程软件中约束文件的关键配置技巧与常见问题。通过基础架构解析、时钟约束实践、物理约束调控及典型问题排查指南,帮助开发者高效掌握国产FPGA开发中的约束文件应用,提升开发效率与设计稳定性。

gin88的博客 908

【Golang】✔️走进 Go 语言✔️ 第十四课 排序

【Golang】✔️走进 Go 语言✔️ 第十四课 排序.

我是小白呀的博客 1435

均值回归 高频交易_基于布林带的均值回归交易策略

BOLL指标是美国股市分析家约翰·布林根据统计学中的标准差原理设计出来的一种非常简单实用的技术分析指标。一般而言,股价的运动总是围绕某一价值中枢(如均线、成本线等)在一定的范围内变动,布林线指标正是在上述条件的基础上,引进了“股价通道”的概念,其认为股价通道的宽窄随着股价波动幅度的大小而变化,而且股价通道又具有变异性,它会随着股价的变化而自动调整。由于之前大部分交易策略都是选股或者趋势追踪的择时,...

weixin_42528534的博客 1458

Go语言原子操作—atomic

在日常开发中,不可避免的会碰到并发场景,在Go语言中处理同步的方法通常是使用锁,但如果是对单一的一个整数操作,这个时候使用锁可能会造成更大的性能开销,而且代码也失去了美观与优雅。这个时候我们可以使用Go语言自带的原子操作,原子操作在Go语言的sync/atomic标准库里面,原子操作是比其他同步技术更基础的一种技术,而且原子操作是无锁的,通常是直接通过CPU指令实现。如果去看其他同步技术的源码可以看到很多技术都是依赖于原子操作的。

CodeJR 1249

基于Xilinx Artix7 的FPGA高级应用 (二):千兆以太网通信(实战篇)第一期

本项目是基于Xlinx Artix7 XC7A35T芯片 以太网芯片选用的是RTL8211EG PHY芯片 MAC 和PHY接口标准是GMII 开发工具是vivado 2018.3 我们先来复习一下以太网的基本通信原理: 当我们的计算机需要与局域网中另外的设备进行通信的时候,需要将数据传输到网卡进行编码,然后传输到线上,经过另一个设备的网卡解码成该设备能读取的数据。 关于以太网协议的知识在原理篇中已经讲过,不再重复,下面直接看接收代码: 首先注意我们的MAC和PHY通信选择的是GMII接口标准,发送数据一

工大技术底层人员的博客 4034

全面分析总结解决Could not transfer artifact org.apache.maven.plugins等此类问题的方法

全面分析总结解决Could not transfer artifact org.apache.maven.plugins,Could not transfer artifact xxx from/to xxx等此类问题的方法

ccjjjjdff的博客 1万+

Go语言并发编程:原子操作与atomic.AddUint64详解

在多线程编程中,数据竞争是一个常见的问题。当多个线程同时访问和修改同一个变量时,可能会导致不可预测的结果。为了确保数据的一致性和安全性,我们需要使用线程安全的操作。在Go语言中,包提供了原子操作,可以用于在并发环境中安全地操作共享变量。是 Go 语言中实现原子递增操作的一种高效方式。它的实现依赖于底层硬件的原子指令和缓存一致性机制,确保在并发环境中对共享变量的操作是安全的。使用原子操作可以避免数据竞争问题,提高程序的可靠性和性能。

2201_75798391的博客 875

拆解歌尔2718硅麦:2.75mm超小封装背后的MEMS技术解析

本文深度解析歌尔2718硅麦的2.75mm超小封装技术,探讨MEMS麦克风在微型化过程中的声学性能与结构可靠性平衡。通过ASIC芯片堆叠、纳米级应力控制等创新技术,歌尔2718在TWS耳机和智能手机中实现卓越性能,同时克服微型化带来的声学挑战。

weixin_28292761的博客 610

[go]原子操作atomic包简介

文章目录简介原子操作与互斥锁区别原子操作增加操作比较并交换操作载入操作atomic.Valuevalue读取value存储 原子操作就是不可中断的操作,这些操作对外表现成一个不可分割的整体,他们要么都执行,要么都不执行,外界是看不到原子操作的中间状态。 简介 go语言通过内置sync/atomic包提供对原子操作的支持,包括(以下XXType为:int32、int64、uint32、uint64、uintptr): 增减操作(AddXXType):保证对操作数的原子增减; 载入操作(LoadXXType)

飞鹰技术 3250

【Simulink教程案例19】基于simulink的扩频通信系统建模与仿真

扩频是一种应用于数字调制信号的调制技术,可以提高传输信号的带宽。扩频通信具有抗干扰能力强,扩频增益越大,抗干扰能力越强。而且扩频通信具有很强的保密性,扩频后信号近似白噪声,功率谱密度也很低。扩频通信可用于多址通信。扩频调制有如下三个特点:① 扩频后信号的带宽远大于信号所需的带宽② 使用扩频码进行扩频调制,扩频码与信号中的数据相互独立③ 在接收端,通过将接收信号与扩频码的同步副本进行相关,实现解扩。

FPGA/MATLAB学习教程/源码/项目合作开发 2197

面经-2023-哲库Zeku-数字芯片设计

面经-2023-哲库Zeku-数字芯片设计

w0shishabi的博客 3907

《7天学会Go并发编程》第7天 go语言并发编程Atomic原子实战操作含ABA问题

目录一、Atomic-原子操作简介二、🍻go语言Atomic源码分析和实战操作2.1🍺🍺🍺 Atomic 关键函数及其释义2.1 🍭🍭🍭atomic实战2.2 🍖🍖🍖atomic原子并发操作2.3 🍟🍟🍟任意数据结构的原子操作三、🍏🍏🍏总结原子操作其实和原子没有什么关系,主要借用的是原子不可分割的概念来强调说明这个操作也不可以被分割。🚗使用并发编程时需要解决的就是临界区(公共资源的修改)问题,抽象的数据操作行为是RAW,WAR,WAW。🥤🥤🥤体现在具体编码过程中,就是.........

alike_u的博客 1116

pip install安装markitdown时出现ERROR: ‘packages/markitdown[all]‘ is not a valid editable requirement解决方案

本文主要介绍了pip install安装markitdown时出现ERROR: ‘packages/markitdown[all]’ is not a valid editable requirement解决方案,希望能对使用markitdown的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 2万+

跟着实例学Go语言(一)

本教程全面涵盖了Go语言基础的各个方面。一共80个例子,每个例子对应一个语言特性点,非常适合新人快速上手。 教程代码示例来自go by example,文字部分来自本人自己的理解。本文是教程系列的第一部分,共计20个例子、10233字。下面的例子演示了如何打印经典的“Hello world”语句,以及运行和编译go代码的方法。 2. Values 下面的代码演示了打印不同类型变量的方法。 3. Variables 下面的例子演示了定义和初始化变量的方法。Go的编译器可以做类型推导,无需显示指定类型。

长三月的游戏开发 985

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

跟着实例学Go语言(二)

本教程全面涵盖了Go语言基础的各个方面。一共80个例子,每个例子对应一个语言特性点,非常适合新人快速上手。 教程代码示例来自go by example,文字部分来自本人自己的理解。本文是教程系列的第二部分,共计20个例子、约1.2万字。下面的例子展示了用interface关键字定义接口。接口是一组方法签名的集合,用于实现多态。Go不像其他语言那样需要通过extend关键字显式指定类型的继承关系。如果一个struct类型实现了interface中定义的所有方法,那么就认为这个struct类型属于interfa

长三月的游戏开发 605

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

跟着deepseek学golang--Go vs Java vs JavaScript三语言的差异

Go/Java在编译期拦截类型错误,JavaScript允许运行时自由转换。Java 14+引入Optional类型,Go推荐通过错误处理避免空指针。保证资源释放,Java需要显式。-Go:强在并发处理和部署效率。

认真,努力,记录学习 1323

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

跟着deepseek学golang--认识golang

Go Modules已解决依赖管理问题,但仍有18%的遗留项目依赖vendor目录(2023年CNCF调研数据)Uber代码规范要求错误必须带堆栈上下文,需使用github.com/pkg/errors。Docker引擎采用Go编写,单个二进制文件仅38MB(v20.10.24版本)通过go mod vendor生成独立依赖目录,保证构建环境纯净。etcd:基于RAFT共识算法,实现10,000+次写操作/秒。同等并发任务下,Go比Java线程模型节省96%内存。不支持元编程,泛型方法仍受限。

认真,努力,记录学习 1420

跟着实例学Go语言(四)

本教程全面涵盖了Go语言基础的各个方面。一共80个例子,每个例子对应一个语言特性点,非常适合新人快速上手。 教程代码示例来自go by example,文字部分来自本人自己的理解。本文是教程系列的第四部分,共计20个例子、约1.5万字。Go提供了Base64编解码的功能。Base64是将二进制数据转换成可读字符串的编码方式。例如我们用记事本打开jpg文件,会看到一串乱码,这个就是Base64转换后的字符串。Base64提供了64种不同的字符,6位编码表示一个字符。 62. Reading File

长三月的游戏开发 569

【Go语言入门指南】零基础入门 go 语言 | Golang 入门指南

这篇文章是我自己亲身经历这样去学go的,本人是从20年的10月份开始入坑go语言的,当时的资料真的少,现在关于go语言的资料已经很多了。我就在把我自己的学习路线稍微梳理一遍,我个人觉得,学完之后,像深信服,b站,得物什么的应该是没什么问题,但如果是字节,腾讯,阿里这种就除了一些硬性条件之外,自己再刷多点题,背多点八股了。

面向生活编程 1万+

【Go语言入门教程】Go语言简介

文章目录Go语言简介Go语言创始人1) Ken Thompson2) Rob Pike3) Robert GriesemerGo 是编译型语言为什么要学习Go语言Go语言吉祥物Go语言的特性有哪些?语法简单并发模型内存分配垃圾回收静态链接标准库工具链Go语言为并发而生哪些项目使用Go语言开发?1) [Docker](http://c.biancheng.net/docker/)2) Go语言3) Kubernetes4) etcd5) beego6) martini7) codis8) delve哪些大公司

qq_41854911的博客 2万+

【跟着我们学Golang】Go语言全平台安装

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34417183的博客 111

【跟着我们学Golang】之面向对象

万物皆对象。学过Java编程的都知道Java是一门面向对象的语言,它拥有封装、继承和多态的特性。那可不可以说,拥有封装、继承和多态这一特性的语言就是面向对象的语言呢? 仔细想来,也确实是这样的,因为封装、继承和多态这三个特征,并不是Java语言的特征,而是面向对象的三大特征。 总结来看,所有包含封装、继承和多态者三大特征的语言都可以说是面向对象的语言。 那么Go语言是否是一门面向对象的语言呢?下面...

架构师专栏 611

从0开始Go语言,用Golang搭建网站

实践是最好的学习方式 零基础通过开发Web服务学习Go语言 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9jb019j4-1638772166928)(https://studygolang.com/img/bVbswsd?w=910&h=892)] 本文适合有一定编程基础,但是没有Go语言基础的同学。 也就是俗称的“骗你”学Go语言系列。 这是一个适合阅读的系列,我希望您能够在车上、厕所、餐厅都阅读它,涉及代码的部分也是精简而实用的。 学习需要动机 Go语言能干什

m0_46426259的博客 4488

Go语言与Java语言对比

宏观看Go与Java的差异 接着,我们来看一下Go语言与Java的差异之处: ``` *.无虚拟机,不跨平台(这里的平台指操作系统)(可以运行多个平台,每个平台打不同的二进制程序包),需要打包编译成对应服务器操作系统版本(windows/linux)的可执行程序(比如windows是exe)。(注:说go跨平台的是指32位和64位相同操作系统之间的跨平台) ​ *.因为Go程序直接打包成操作系统可执行的文件,没有虚拟机在中间转换的一层,所以理论上执行效率会更高(理论上更高,实际情况需具

Add小兵的博客 6871

开篇词 | 跟着学,你也能成为Go语言高手

你好,我是郝林。今天想跟你聊聊我和Go语言的故事。Go语言是由Google出品的一门通用型计算机编程语言。作为在近年来快速崛起的编程语言,Go已经成功跻身主流编程语言的行列。它的种种亮点都受到了广大编程爱好者的追捧。特别是一些对团队协作有较高要求的公司和技术团队,已经在有意识地大量使用Go语言编程,并且,使用的人群还在持续迅猛增长。我个人很喜欢Go语言。我是从2012年底开始关注Go语言的,虽然这...

优快云学习 398

【跟着我们学Golang】之异常处理

Java中的异常分为Error和Exception来处理,这里也以错误和异常两种,来分别讲一讲Go的异常处理。 Go 语言没有类似 Java 或 .NET 中的异常处理机制,虽然可以使用 defer、panic、recover 模拟,但官方并不主张这样做。Go 语言的设计者认为其他语言的异常机制已被过度使用,上层逻辑需要为函数发生的异常付出太多的资源。同时,如果函数使用者觉得错误处理很麻烦而忽略...

架构师专栏 968
上一篇: 跟着实例学Go语言(二)
下一篇: 跟着实例学Go语言(四)
长三月
博客等级 码龄9年 228粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值