Go内部培训——节点解析51-60

51. Go 时间格式化和解析

  • Go使用模式匹配的方式来支持日期格式化和解析。
package main
import "fmt"
import "time"
func main() {
p := fmt.Println
// 这里有一个根据RFC3339来格式化日期的例子
t := time.Now()
p(t.Format("2006-01-02T15:04:05Z07:00"))
// Format 函数使用一种基于示例的模式匹配方式,
// 它使用已经格式化的时间模式来决定所给定参数
// 的输出格式
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"))
// 对于纯数字表示的时间来讲,你也可以使用标准
// 的格式化字符串的方式来格式化时间
fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second())
// 时间解析也是采用一样的基于示例的方式
withNanos := "2006-01-02T15:04:05.999999999-07:00"
t1, e := time.Parse(
withNanos,
"2012-11-01T22:08:41.117442+00:00")
p(t1)
kitchen := "3:04PM"
t2, e := time.Parse(kitchen, "8:41PM")
p(t2)
// Parse将返回一个错误,如果所输入的时间格式不对的话
ansic := "Mon Jan _2 15:04:05 2006"
_, e = time.Parse(ansic, "8:41PM")
p(e)
// 你可以使用一些预定义的格式来格式化或解析时间
p(t.Format(time.Kitchen))
}

52. Go数值

  • Go有很多种数据类型,包括字符串类型,整型,浮点型,布尔型等等,这里有几个基础的例子。
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(true || false)
fmt.Println(!true)
}

53. Go 数字解析

  • 从字符串解析出数字是一个基本的而且很常见的任务。
  • Go内置的 strconv 提供了数字解析功能。
package main
import "strconv"
import "fmt"
func main() {
// 使用ParseFloat解析浮点数,64是说明使用多少位
// 精度来解析
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f)
// 对于ParseInt函数,0 表示从字符串推断整型进制,
// 则表示返回结果的位数
i, _ := strconv.ParseInt("123", 0, 64)
fmt.Println(i)
// ParseInt能够解析出16进制的数字
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)
}

54. Go 数组

  • 数组是一个具有 相同数据类型 的元素组成的 固定长度 的 有序集合 。
    在Go语言中,数组是值类型,长度是类型的组成部分,也就是说" [10]int “和“ [20]int ”是完全不同
    的两种数组类型。
    同类型的两个数组支持”==“和”!="比较,但是不能比较大小。
    数组作为参数时,函数内部不改变数组内部的值,除非是传入数组的指针。
    数组的指针:*[3]int
    指针数组:[2]*int
package main
import "fmt"
func main() {
// 这里我们创建了一个具有5个元素的整型数组
// 元素的数据类型和数组长度都是数组的一部分
// 默认情况下,数组元素都是零值
// 对于整数,零值就是0
var a [5]int
fmt.Println("emp:", a)
// 我们可以使用索引来设置数组元素的值,就像这样
// "array[index] = value" 或者使用索引来获取元素值,
// 就像这样"array[index]"
a[4] = 100
fmt.Println("set:", a)
fmt.Println("get:", a[4])
// 内置的len函数返回数组的长度
fmt.Println("len:", len(a))
// 这种方法可以同时定义和初始化一个数组
b := [5]int{1, 2, 3, 4, 5}
fmt.Println("dcl:", b)
// 数组都是一维的,但是你可以把数组的元素定义为一个数组
// 来获取多维数组结构
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
}

55. Go 随机数

  • Go的 math/rand 包提供了伪随机数的生成。
package main
import "fmt"
import "math/rand"
func main() {
// 例如`rand.Intn`返回一个整型随机数n,0<=n<100
fmt.Print(rand.Intn(100), ",")
fmt.Print(rand.Intn(100))
fmt.Println()
// `rand.Float64` 返回一个`float64` `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()
// 为了使随机数生成器具有确定性,可以给它一个seed
s1 := rand.NewSource(42)
r1 := rand.New(s1)
fmt.Print(r1.Intn(100), ",")
fmt.Print(r1.Intn(100))
fmt.Println()
// 如果源使用一个和上面相同的seed,将生成一样的随机数
s2 := rand.NewSource(42)
r2 := rand.New(s2)
fmt.Print(r2.Intn(100), ",")
fmt.Print(r2.Intn(100))
fmt.Println()
}

56. Go通道的同步功能

  • 我们使用通道来同步协程之间的执行。
    下面的例子是通过获取同步通道数据来阻塞程序执行的方法来等待另一个协程运行结束的。
    也就是说main函数所在的协程在运行到
    <-don
    e 语句的时候将一直等待worker函数所在的协程执行完
    成,向通道写入数据才会(从通道获得数据)继续执行。
package main
import "fmt"
import "time"
// 这个worker函数将以协程的方式运行
// 通道`done`被用来通知另外一个协程这个worker函数已经执行完成
func worker(done chan bool) {
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
// 向通道发送一个数据,表示worker函数已经执行完成
done <- true
}
func main() {
// 使用协程来调用worker函数,同时将通道`done`传递给协程
// 以使得协程可以通知别的协程自己已经执行完成
done := make(chan bool, 1)
go worker(done)
// 一直阻塞,直到从worker所在协程获得一个worker执行完成的数据
<-done
}

57. Go通道方向

  • 当使用通道作为函数的参数时,你可以指定该通道是只读的还是只写的。这种设置有时候会提高程序的参
    数类型安全。
package main
import "fmt"
// 这个ping函数只接收能够发送数据的通道作为参数,试图从这个通道接收数据
// 会导致编译错误,这里只写的定义方式为`chan<- string`表示这个类型为
// 字符串的通道为只写通道
func ping(pings chan<- string, msg string) {
pings <- msg
}
// pong函数接收两个通道参数,一个是只读的pings,使用`<-chan string`定义
// 另外一个是只写的pongs,使用`chan<- string`来定义
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)
}

58. Go通道缓冲

  • Go通道缓冲
    默认情况下,通道是不带缓冲区的。
    发送端发送数据,同时必须又接收端相应的接收数据。
    而带缓冲区的通道则允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据
    可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
    不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就
    无法再发送数据了。
package main
import "fmt"
func main() {
// 这里我们定义了一个可以存储字符串类型的带缓冲通道
// 缓冲区大小为2
messages := make(chan string, 2)
// 因为messages是带缓冲的通道,我们可以同时发送两个数据
// 而不用立刻需要去同步读取数据
messages <- "buffered"
messages <- "channel"
// 然后我们和上面例子一样获取这两个数据
fmt.Println(<-messages)
fmt.Println(<-messages)
}

59. Go 通道选择Select

  • Go的select关键字可以让你同时等待多个通道操作,将协程(goroutine),通道(channel)和select结
    合起来构成了Go的一个强大特性。
package main
import "time"
import "fmt"
func main() {
// 本例中,我们从两个通道中选择
c1 := make(chan string)
c2 := make(chan string)
// 为了模拟并行协程的阻塞操作,我们让每个通道在一段时间后再写入一个值
go func() {
time.Sleep(time.Second * 1)
c1 <- "one"
}()
go func() {
time.Sleep(time.Second * 2)
c2 <- "two"
}()
// 我们使用select来等待这两个通道的值,然后输出
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}

60. Go 写入文件

  • Go将数据写入文件的方法和上面介绍过的读取文件的方法很类似。
package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
// 首先看一下如何将一个字符串写入文件
d1 := []byte("hello\ngo\n")
err := ioutil.WriteFile("/tmp/dat1", d1, 0644)
check(err)
// 为了实现细颗粒度的写入,打开文件后再写入
f, err := os.Create("/tmp/dat2")
check(err)
// 在打开文件后通常应该立刻使用defer来调用
// 打开文件的Close方法,以保证main函数结束
// 后,文件关闭
defer f.Close()
// 你可以写入字节切片
d2 := []byte{115, 111, 109, 101, 10}
n2, err := f.Write(d2)
check(err)
fmt.Printf("wrote %d bytes\n", n2)
// 也可以使用`WriteString`直接写入字符串
n3, err := f.WriteString("writes\n")
fmt.Printf("wrote %d bytes\n", n3)
// 调用Sync方法来将缓冲区数据写入磁盘
f.Sync()
// `bufio`除了提供上面的缓冲读取数据外,还
// 提供了缓冲写入数据的方法
w := bufio.NewWriter(f)
n4, err := w.WriteString("buffered\n")
n4, err := w.WriteString("buffered\n")
fmt.Printf("wrote %d bytes\n", n4)
// 使用Flush方法确保所有缓冲区的数据写入底层writer
w.Flush()
}

猜你喜欢

转载自blog.csdn.net/boss2967/article/details/85121555