越简洁越好或者 长代码往往不是最好的. 试着使用能自解释的最短的变量名. - 用
MarshalIndent ,别用 MarshalWithIndentation .
别忘了包名会出现在你选择的标识符前面 - In package
encoding/json we find the type Encoder , not JSONEncoder .
- It is referred as
json.Encoder .
有多个文件的包 需要将一个包分散到多个文件中吗? 标准库中 net/http 包有47个文件,共计 15734 行. net/http/cookie.go 和 net/http/cookie_test.go 都是 http 包的一部分.
测试代码 只有 在测试时才会编译. 如果一个包中有多个文件, 可以很方便的创建一个 doc.go 文件,包含包文档信息. 让包可以”go get”到一些包将来可能会被复用,另外一些不会. 定义了一些网络协议的包可能会在开发一个可执行命令时复用. github.com/bradfitz/camlistore 接口你需要什么让我们以之前的Gopher类型为例 1 2 3 4 5 | type Gopher struct {
Name string
Age int32
FurColor color.Color
}
|
我们可以定义这个方法 1 | func (g *Gopher) DumpToFile(f *os.File) error {
|
但是使用一个具体的类型会让代码难以测试,因此我们使用接口. 1 | func (g *Gopher) DumpToReadWriter(rw io.ReadWriter) error {
|
进而,由于使用的是接口,我们可以只请求我们需要的. 1 | func (g *Gopher) DumpToWriter(f io.Writer) error {
|
让独立的包彼此独立1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import (
"code.google.com/p/go.talks/2013/bestpractices/funcdraw/drawer"
"code.google.com/p/go.talks/2013/bestpractices/funcdraw/parser"
)
f, err := parser.Parse(text)
if err != nil {
log.Fatalf( "parse %q: %v" , text, err)
}
m := drawer.Draw(f, *width, *height, *xmin, *xmax)
err = png.Encode(os.Stdout, m)
if err != nil {
log.Fatalf( "encode image: %v" , err)
}
|
解析1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | type ParsedFunc struct {
text string
eval func(float64) float64
}
func Parse(text string) (*ParsedFunc, error) {
f, err := parse(text)
if err != nil {
return nil, err
}
return &ParsedFunc{text: text, eval: f}, nil
}
func (f *ParsedFunc) Eval(x float64) float64 { return f.eval(x) }
func (f *ParsedFunc) String () string { return f.text }
|
描绘1 2 3 4 5 6 7 8 | import (
"image"
"code.google.com/p/go.talks/2013/bestpractices/funcdraw/parser"
)
func DrawParsedFunc(f parser.ParsedFunc) image.Image {
|
使用接口来避免依赖. import "image"
// Function represent a drawable mathematical function.
type Function interface {
Eval(float64) float64
}
// Draw draws an image showing a rendering of the passed Function.
func Draw(f Function) image.Image { 测试使用接口而不是具体类型让测试更简洁. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package drawer
import (
"math"
"testing"
)
type TestFunc func(float64) float64
func (f TestFunc) Eval(x float64) float64 { return f(x) }
var (
ident = TestFunc(func(x float64) float64 { return x })
sin = TestFunc(math.Sin)
)
func TestDraw_Ident(t *testing.T) {
m := Draw(ident)
|
在接口中避免并发1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | func doConcurrently(job string, err chan error) {
go func() {
fmt.Println( "doing job" , job)
time.Sleep( 1 * time.Second)
err <- errors.New( "something went wrong!" )
}()
}
func main() {
jobs := []string{ "one" , "two" , "three" }
errc := make(chan error)
for _, job := range jobs {
doConcurrently(job, errc)
}
for _ = range jobs {
if err := <-errc; err != nil {
fmt.Println(err)
}
}
}
|
如果我们想串行的使用它会怎样? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | func do (job string) error {
fmt.Println( "doing job" , job)
time.Sleep( 1 * time.Second)
return errors.New( "something went wrong!" )
}
func main() {
jobs := []string{ "one" , "two" , "three" }
errc := make(chan error)
for _, job := range jobs {
go func(job string) {
errc <- do (job)
}(job)
}
for _ = range jobs {
if err := <-errc; err != nil {
fmt.Println(err)
}
}
}
|
暴露同步的接口,这样异步调用这些接口会简单. |