论golang的文档即代码

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

GO TEST

如果提供一个库,或者提供了一个模块,如何给使用者描述这个API的用法?一般都是给文档,但是文档非常容易不同步,在golang中,有更高级的做法,也是最好的做法。

go-fdkaac为例,这个是一个go binding,调用了lib-fdkaac的c函数,提供aac的codec的一个库。

首先,由于用静态库的方式引用,涉及到了如何下载fdkaac的c代码和编译,需要在doc中说明,也就是README.md中说明Usagehttps://github.com/winlinvip/go-fdkaac#usage

在Usage中,准备好代码和环境后,就只需要链接到使用的examples:

而这个使用说明本身就是utest,有期望值,可以运行:

winlin:go-fdkaac winlin$ go test ./...
?       github.com/winlinvip/go-fdkaac  [no test files]
ok      github.com/winlinvip/go-fdkaac/dec  0.008s
winlin:go-fdkaac winlin$ 

文档变成了可以执行的代码,或者说,没有了经常变化的文档,只有代码,golang这点做得真是perfect!

而example的package,和API的package是不一样的。这个和utest是不一样的,utest因为要访问package内部的内容,所以和API同一个package,比较方便。example因为是给用户用的例子,当然和API的package不能一样,也不可能一样。

GOLANG的Example,强迫API设计者,能从User角度出发,将API设计得很简单易懂,因为复杂的API不好用在写Example时很容易就发现了:

package dec_test

import (
    "fmt"
    "github.com/winlinvip/go-fdkaac/dec"
)

func ExampleAacDecoder_RAW() {
    var err error
    d := dec.NewAacDecoder()

    asc := []byte{0x12, 0x10}
    if err := d.InitRaw(asc); err != nil {
        fmt.Println("init decoder failed, err is", err)
        return
    }
    defer d.Close()

    // directly decode the frame to pcm.
    var pcm []byte
    if pcm,err = d.Decode([]byte{
        0x21, 0x17, 0x55, 0x35, 0xa1, 0x0c, 0x2f, 0x00, 0x00, 0x50, 0x23, 0xa6, 0x81, 0xbf, 0x9c, 0xbf,
        0x13, 0x73, 0xa9, 0xb0, 0x41, 0xed, 0x60, 0x23, 0x48, 0xf7, 0x34, 0x07, 0x12, 0x53, 0xd8, 0xeb,
        0x49, 0xf4, 0x1e, 0x73, 0xc9, 0x01, 0xfd, 0x16, 0x9f, 0x8e, 0xb5, 0xd5, 0x9b, 0xb6, 0x49, 0xdb,
        0x35, 0x61, 0x3b, 0x54, 0xad, 0x5f, 0x9d, 0x34, 0x94, 0x88, 0x58, 0x89, 0x33, 0x54, 0x89, 0xc4,
        0x09, 0x80, 0xa2, 0xa1, 0x28, 0x81, 0x42, 0x10, 0x48, 0x94, 0x05, 0xfb, 0x03, 0xc7, 0x64, 0xe1,
        0x54, 0x17, 0xf6, 0x65, 0x15, 0x00, 0x48, 0xa9, 0x80, 0x00, 0x38}); err != nil {
        fmt.Println("decode failed, err is", err)
        return
    }

    fmt.Println("SampleRate:", d.SampleRate())
    fmt.Println("FrameSize:", d.FrameSize())
    fmt.Println("NumChannels:", d.NumChannels())
    fmt.Println("AacSampleRate:", d.AacSampleRate())
    fmt.Println("Profile:", d.Profile())
    fmt.Println("AudioObjectType:", d.AudioObjectType())
    fmt.Println("ChannelConfig:", d.ChannelConfig())
    fmt.Println("Bitrate:", d.Bitrate())
    fmt.Println("AacSamplesPerFrame:", d.AacSamplesPerFrame())
    fmt.Println("AacNumChannels:", d.AacNumChannels())
    fmt.Println("ExtensionAudioObjectType:", d.ExtensionAudioObjectType())
    fmt.Println("ExtensionSamplingRate:", d.ExtensionSamplingRate())
    fmt.Println("NumLostAccessUnits:", d.NumLostAccessUnits())
    fmt.Println("NumTotalBytes:", d.NumTotalBytes())
    fmt.Println("NumBadBytes:", d.NumBadBytes())
    fmt.Println("NumTotalAccessUnits:", d.NumTotalAccessUnits())
    fmt.Println("NumBadAccessUnits:", d.NumBadAccessUnits())
    fmt.Println("SampleBits:", d.SampleBits())
    fmt.Println("PCM:", len(pcm))

    // Output:
    // SampleRate: 44100
    // FrameSize: 1024
    // NumChannels: 2
    // AacSampleRate: 44100
    // Profile: 1
    // AudioObjectType: 2
    // ChannelConfig: 2
    // Bitrate: 31352
    // AacSamplesPerFrame: 1024
    // AacNumChannels: 2
    // ExtensionAudioObjectType: 0
    // ExtensionSamplingRate: 0
    // NumLostAccessUnits: 0
    // NumTotalBytes: 91
    // NumBadBytes: 0
    // NumTotalAccessUnits: 1
    // NumBadAccessUnits: 0
    // SampleBits: 16
    // PCM: 4096
}

这个API设计时,最初是和fdkaac一样,有Fill([]byte)然后是Decode(),分成了两步,可以多次Fill。后来发现这个实在不好用,不如直接Decode([]byte),可以用Decode(nil)进去。


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

本文来自:CSDN博客

感谢作者:winlinvip

查看原文:论golang的文档即代码

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

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