golang小程序试验(五)

壬癸甲乙 · · 2317 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

1. golang的指针

可以将unsafe.Pointer转换成uintptr,然后变相做指针运算

package main

import "fmt"
import "unsafe"

type User struct {
	Id   int
	Name string
}

func main() {
	u := &User{1, "tom"}
	var up uintptr = uintptr(unsafe.Pointer(u)) + unsafe.Offsetof(u.Name)
	var name *string = (*string)(unsafe.Pointer(up))
	fmt.Println(*name)
}

2. package io

实现了io.Reader或io.Writer接口的类型(导出的类型):

  • os.File 同时实现了io.Reader和io.Writer
  • strings.Reader 实现了io.Reader
  • bufio.Reader/Writer 分别实现了io.Reader和io.Writer
  • bytes.Buffer 同时实现了io.Reader和io.Writer
  • bytes.Reader 实现了io.Reader
  • compress/gzip.Reader/Writer 分别实现了io.Reader和io.Writer
  • crypto/cipher.StreamReader/StreamWriter 分别实现了io.Reader和io.Writer
  • crypto/tls.Conn 同时实现了io.Reader和io.Writer
  • encoding/csv.Reader/Writer 分别实现了io.Reader和io.Writer
  • mime/multipart.Part 实现了io.Reader
以上类型中,常用的类型有:os.File、strings.Reader、bufio.Reader/Writer、bytes.Buffer、bytes.Reader

WriteAt()方法简单示例:

file, err := os.Create("writeAt.txt")
if err != nil {
    panic(err)
}
defer file.Close()
file.WriteString("Golang中文社区——这里是多余的")
n, err := file.WriteAt([]byte("Go语言学习园地"), 24)
if err != nil {
    panic(err)
}
fmt.Println(n)

file.WriteString("Golang中文社区——这里是多余的") 往文件中写入Golang中文社区——这里是多余的;之后file.WriteAt([]byte("Go语言学习园地"), 24) 在文件流的offset=24处写入Go语言学习园地(会覆盖该位置的内容)。

ReadFrom()方法简单示例:

file, err := os.Open("writeAt.txt")
if err != nil {
    panic(err)
}
defer file.Close()
writer := bufio.NewWriter(os.Stdout)
writer.ReadFrom(file)
writer.Flush()
WriteTo()方法示例:
reader := bytes.NewReader([]byte("Go语言学习园地"))
reader.WriteTo(os.Stdout)
Seek()方法示例:
reader := strings.NewReader("Go语言学习园地")
reader.Seek(-6, os.SEEK_END)
r, _, _ := reader.ReadRune()
fmt.Printf("%c\n", r)

在标准库中,有如下类型实现了io.ByteReader或io.ByteWriter:

  • bufio.Reader/Writer 分别实现了io.ByteReader和io.ByteWriter
  • bytes.Buffer 同时实现了io.ByteReader和io.ByteWriter
  • bytes.Reader 实现了io.ByteReader
  • strings.Reader 实现了io.ByteReader

接下来的示例中,我们通过bytes.Buffer来一次读取或写入一个字节(主要代码):

var ch byte
fmt.Scanf("%c\n", &ch)

buffer := new(bytes.Buffer)
err := buffer.WriteByte(ch)
if err == nil {
    fmt.Println("写入一个字节成功!准备读取该字节……")
    newCh, _ := buffer.ReadByte()
    fmt.Printf("读取的字节:%c\n", newCh)
} else {
    fmt.Println("写入错误")
}
Pipe()方法和PipeReader、PipeWriter结构的示例:
func main() {
    Pipe()
}

func Pipe() {
    pipeReader, pipeWriter := io.Pipe()
    go PipeWrite(pipeWriter)
    go PipeRead(pipeReader)
    time.Sleep(1e7)
}

func PipeWrite(pipeWriter *io.PipeWriter) {
    var (
        i   = 0
        err error
        n int
    )
    data := []byte("Go语言学习园地")
    for _, err = pipeWriter.Write(data); err == nil; n, err = pipeWriter.Write(data) {
        i++
        if i == 3 {
            pipeWriter.CloseWithError(errors.New("输出3次后结束"))
        }
    }
    fmt.Println("close 后输出的字节数:", n, " error:",  err)
}

func PipeRead(pipeReader *io.PipeReader) {
    var (
        err error
        n   int
    )
    data := make([]byte, 1024)
    for n, err = pipeReader.Read(data); err == nil; n, err = pipeReader.Read(data) {
        fmt.Printf("%s\n", data[:n])
    }
    fmt.Println("writer 端 closewitherror后:", err)
}
Copy()方法示例:
package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    io.Copy(os.Stdout, strings.NewReader("Go语言学习园地"))
    io.Copy(os.Stdout, os.Stdin)
    fmt.Println("Got EOF -- bye")
}

3. 程序结构

假设有一个服务的大致实现是这样的:

type Service struct {
wg sync.WaitGroup
}
func (p *Service) Start() {
p.wg.Add(1)
go p.run()
}
func (p *Service) Close() {
// ...
p.wg.Wait()
}
func (p *Service) run() {
defer p.wg.Done()
// ....
}
其中run()是服务的主要逻辑实现。这样写法的问题是wg的Add和Done函数调用分离了,容易导致在以后的代码维护中不小心就导致Add和Done的调用不匹配从而Wait执行的结果不符合预期。从代码组织的方式上来说,应该把功能相关的代码尽可能地放在一起。

type Service struct {
wg sync.WaitGroup
}
func (p *Service) Start() {
p.wg.Add(1)
go func() {
p.run()
p.wg.Done()
}()
}
func (p *Service) Close() {
// ...
p.wg.Wait()
}
func (p *Service) run() {
// ....
}
这个其实也算常识了,写过些代码的人可能都知道。但是在实际的代码中,我们往往还会发现类似这样的一些不好的写法。因此,对于这些惯用法(或者升级为代码规范),我觉得更重要的不是了解知道,而是执行和遵守。

有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:壬癸甲乙

查看原文:golang小程序试验(五)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

2317 次点击  
加入收藏 微博
1 回复  |  直到 2017-10-11 20:19:14
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传