GO 语言学习的五个阶段(带例子) 返回原文

英文原文:The 5 stages of learning Go (with examples)

Francesc (@francesc) is a member of the Go core team and a developer advocate for Google Cloud Platform. He’s a lover of programming languages, a master of technical instruction at Google, and one of the creators of the Go tour. This talk was inspired by another talk from Raquel Vélez at JSConf. Slides for this talk have been posted here. Sourcegraph is building the next generation of programming collaboration tools for searching, exploring, and reviewing code. We attended GopherCon India to share how we use Go and learn from how others are using it, and were honored to coordinate the liveblog of the talks.

译者信息 Francesc (@francesc) 是 Go 核心团队的一员, 是提倡 Google Cloud 平台的开发者. 他是一个编程语言的爱好者, Google的技术指导大师, Go tour的创造者之一. 这个讨论的灵感来自于另一个 Raquel Vélez 在 JSConf. Slides 的讨论,这个讨论已经发到了这里. Sourcegraph 是下一代编程协作工具, 用于搜索, 探索, 和审查代码. 我们参加GopherCon India 来分享我们是怎样使用 Go 并学习别人是怎样使用它的, 对配合liveblog的这次讨论我们深感荣幸.

As a developer advocate on the Go team, Francesc has probably interacted with more Go programmers than almost anyone else in the world. From this unique vantage point, he has seen 5 general stages in the evolution of programmers working in Go. These stages apply to how programmers progress through other languages, too. Understanding where you are in this evolution can help you figure out the most effective ways to improve and avoid common pitfalls that befall students of programming languages at every level. Editor’s note: this post has interactive code snippets for each phase of this evolution. Clicking on any function name jumps you to the definition in code for further exploration. Scroll down to see them.

译者信息 作为Go团队的开发者之一,Francesc可能比世界上其他人接触到的Go语言程序员都要多。正因为有了这样的有利条件,他把Go语言的学习过程划分为5个阶段。 这些阶段对于其他语言的学习也是成立的。理解自己处于哪个阶段,可以帮助你找到提高自己的最有效的方法,也可以避免每个阶段学习过程中的常见陷阱。 编者按:这篇文章对于每一个学习阶段都给出了交互式的代码片段。点击函数名你就可以跳到具体的函数定义,方便进行深入的研究。请看下文。

Here the 5 phases in the evolution of a Gopher:

  • Phase 1 (the newcomer): You just learned the language. You’ve gone through a few tutorials or workshops, you understand basic syntax, and you can write short snippets of code.
  • Phase 2 (the explorer): You can write a complete program, but don’t understand some more advanced language features like channels. You haven’t yet written a large project in Go.
  • Phase 3 (the builder): You’re proficient in Go, you’re using Go in production to solve a specific and complete problem. You have a strong command of the common patterns and idioms in the language community. Go is a strong tool in your programming toolbelt.
  • Phase 4 (the expert): You understand the design choices and motivations behind the language. You grok the philosophy of simplicity and composability.
  • The advocate: You’re actively sharing your knowledge and understanding of the language with others. You’re a voice in the community, a participant on mailing lists and chatrooms, and you’re giving talks at conferences. Being an advocate is not really a separate stage, but a role you can fill at any of the other stages.

译者信息 这里是GO程序员的五个进化阶段:

  • 第一个阶段(菜逼): 刚刚学习了这门语言。 已经通过一些教程或者培训班了解基本的语法,可以写短的代码片段。
  • 第二个阶段 (探索者): 可以写一个完整的程序,但不懂一些更高级的语言特征,比如“channels”。还没有使用GO写一个大项目。
  • 第三个阶段(大手): 你能熟练的使用Go, 能够用GO去解决,生产环境中一个具体和完整的问题。已经形成了一套自己的惯用法和常用代码库。在你的编码方案中Go是一个非常好用的工具。
  • 第四阶段 (大神): 绝逼清楚Go语言的设计选择和背后的动机。能理解的简洁和可组合性哲学。
  • 布道师: 积极地与他人分享关于Go语言知识和你对Go语言的理解。在各种合适的场所发出自己的声音, 参与邮件列表、建立QQ群、做专题报告。成为一个布道者不见得是一个完全独立的阶段,这个角色可以在上述的任何一个阶段中。

Phase 1: the newcomer Newcomers are at the stage where they’re creating small programs and toy projects in Go. They should take advantage of the Go tour, the Go playground, the docs, and the mailing list (golang-nuts). func main() { fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))} View in context func main in golang/example on ✱ Sourcegraph An interactive snippet from hello.go in the golang/example repository, which contains simple examples of small Go programs. Click around to explore the code.

译者信息

第一阶段: 菜逼 菜鸟在这个阶段使用Go去创建一些小项目或者玩具项目。他们应该会利用到Go tour, Go playground, Go文档, 和邮件列表(golang-nuts). func main() { fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))} 查看上下文

func main in golang/example on ✱ Sourcegraph

这是Go语言写的简单例子,这个代码段来自golang/example 代码库里面的 hello.go 。 点击就可以查看完整代码撸。

An important skill newcomers should develop is learning how to ask questions. A lot of people new to the mailing list say things like, “Hey, this doesn’t work,” without providing enough context to enable others to understand and help fix their problem. At the opposite end of the spectrum are those who copy and paste hundreds of lines of code into a forum post and haven’t invested the time to come up with a focused example that illustrates their problem. Also, you should rarely copy and paste code directly into the forum. Instead use the “share” button of the Go playground to link to snippets of code that others can edit and run directly in their browser.

译者信息 一项重要的技能,新人应该试着学习如何正确提问。很多新人在邮件列表里面这样说“嘿,这报错了”,这并没有提供足够的信息,让别人能理解并帮助他们解决问题。别人看到的是一个粘贴了几百行的代码的帖子,并没有花费精力来重点说明所遇到的问题。 所以, 应该尽量避免直接粘贴代码到论坛。而应该使用可以编辑并且可以在浏览器中直接运行的Go playground的“分享”按钮链接到代码片段。

Phase 2: the explorer The explorer has written some small projects in Go, but still gets lost sometimes. They might not fully understand or know how to use more advanced language features like channels. They still have many things to learn, but know enough to build useful things. They are starting to get a sense of the potential of Go and are excited about what they’ll be able to build in the language.

Within the explorer phase, you typically go through two steps. First, you ascend to the Peak of Inflated Expectations. You think you can do everything in Go, but without really understanding or grokking the Go ethos yet. You are probably trying to apply the idioms and patterns you know from other languages in Go code, and you don’t yet have a strong sense of what constitutes idiomatic Go. You try to undertake tasks like “migrate framework X from language Y to Go”.

译者信息

Phase 2: the explorer 探索者已经可以使用Go写一些小的软件,但有时仍然会有些迷茫。他们可能不完全明白怎么使用Go的高级特性,比如通道。虽然他们还有很多东西要学习,但已掌握的足够做一些有用的事情了!他们开始对Go的潜能有感觉了,并对它们能使用Go创建的东西感到兴奋。

在探索阶段通常会经历两个步骤。第一,膨胀的预期达到顶点,你觉得可以用Go做所有的事情,但还并不能明白或领悟到Go的真谛。你大概会用所熟悉的语言的模式和惯用语来写Go代码,但对于什么是地道的Go,还没有比较强烈的感觉。你开始尝试着手干这样的事情--“迁移架构X,从Y语言到Go语言”。

Following the Peak of Inflated Expectations is the Trough of Disillusionment. You miss feature X from language Y. You haven’t fully bought into idiomatic Go. You are still trying to write in the style of other programming languages and are getting frustrated. You may use the reflect and unsafe packages a lot. This is not idiomatic Go. Idiomatic Go tends to avoid things that are too “magical”. The Martini web framework is an example of a project that exemplifies the explorer phase. Martini was an early Go web framework that adopted a lot of concepts from Ruby web frameworks (like dependency injection). It received a lot of excitement from the community initially, but eventually had many issues around performance and debuggability. Jeremy Saenz (@codegangsta), the creator of Martini, responded constructively to feedback from the Go community and wrote another library called Negroni that follows more idiomatic Go conventions. func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed.

logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) logger.Fatalln(http.ListenAndServe(addr, m))} View in context (*Martini).RunOnAddr in go-martini/martini on ✱ Sourcegraph Interactive code snippet from the Martini web framework, an example of non-idiomatic Go. Note the dependency injection implemented via the reflect package. func TestNegroniServeHTTP(t *testing.T) { result := "" response := httptest.NewRecorder()

n := New() n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "foo" next(rw, r) result += "ban" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bar" next(rw, r) result += "baz" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bat" rw.WriteHeader(http.StatusBadRequest) }))

n.ServeHTTP(response, (*http.Request)(nil))

expect(t, result, "foobarbatbazban") expect(t, response.Code, http.StatusBadRequest)} View in context func TestNegroniServeHTTP in codegangsta/negroni on ✱ Sourcegraph Interactive code snippet demonstrating use of the Negroni library, an example of more idiomatic Go.

译者信息 到达预期膨胀的顶点之后,你会遇到理想幻灭的低谷。你开始想念语言Y的特性X,此时你还没有完全的掌握地道的Go。你还在用其他编程语言的风格来写Go语言的程序,你甚至开始觉得沮丧。你可能在大量使用reflect和unsafe这两个包,但这不是地道的Go。地道的Go不会使用那些魔法一样的东西。 这个探索阶段产生的项目的一个很好的例子就是Martini Web框架。Martini是一个Go语言的早期Web框架,它从Ruby的Web框架当中吸收了很多思想(比如依赖注入)。最初,这个框架在社区中引起了强烈的反响,但是它逐渐在性能和可调试性上受到了一些批评。Martini框架的作者Jeremy Saenz积极响应这些来自Go社区的反馈,写了一个更加符合Go语言规范的库Negroni

func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed.

logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) logger.Fatalln(http.ListenAndServe(addr, m))} 查看上下文

(*Martini).RunOnAddr in go-martini/martini on ✱ Sourcegraph

来自Martini框架的交互式代码片段,它是不地道的Go的例子。注意用反射包实现的依赖注入

func TestNegroniServeHTTP(t *testing.T) { result := "" response := httptest.NewRecorder()

n := New() n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "foo" next(rw, r) result += "ban" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bar" next(rw, r) result += "baz" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bat" rw.WriteHeader(http.StatusBadRequest) }))

n.ServeHTTP(response, (*http.Request)(nil))

expect(t, result, "foobarbatbazban") expect(t, response.Code, http.StatusBadRequest)} 查看上下文

func TestNegroniServeHTTP in codegangsta/negroni on * Sourcegraph

来自Negroni库的交互式代码片段,它是地道的Go的例子

Many other languages rely heavily on third-party libraries to deliver core functionality like HTTP handling. One thing that distinguishes Go is the power of its standard library. If you think the Go standard library is not powerful enough to do what you want to do, you might be wrong. The Go standard library is incredibly powerful, and it’s worth reading through its code to learn the patterns of how it implements things. func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})} View in context (*Server).ListenAndServe in golang/go on ✱ Sourcegraph An interactive snippet of the ListenAndServe method in the Go standard library. If you’ve written Go code, you’ve probably called this function many times, but have you bothered to see how it’s written? Go ahead and click around in the snippet above. The disillusionment of the Trough of Disillusionment comes from the fact that you are still thinking in the patterns of other languages and you haven’t yet fully explored much of what Go offers. Here are some fun things you can do to avoid stalling and dive further into cool things you can do in the language.

译者信息 其他语言在提供一些核心功能,比如HTTP处理的时候,往往需要依赖第三方库。但是Go语言在这一点上很不同,它的标准库非常强大。如果你认为Go标准库没有强大到可以做你想做的事情,那么我说你错了。Go语言标准库难以置信的强大,值得你花时间阅读它的代码,学习它实现的模式。 func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})} 在上下文中查看

(Server).ListenAndServe in golang/go on Sourcegraph

Go标准库中的ListenAndServe函数片段。如果你写过Go程序,你可能已经调用过这个函数很多次了,但是你曾经花时间看过它的实现么?去点击上面的代码片段吧。 幻灭的低谷中的幻灭感来自于这样的事实:你还在用其他语言的模式来想问题,而且你还没有完全探索过Go能提供给你什么。下面是一些好玩的事情,你可以做一下来打破困境,进一步探索这门语言中好玩的事。

go generate Check out go generate. go generate is a command that you can use to auto-generate Go code. You can use it in conjunction with metaprograms like jsonenums (a library to auto-generate JSON marshalling boilerplate code for enum types) to automate the writing of tedious code. The Go standard library has a great API for parsing the AST, which makes metaprogramming tools simple and easy to write. This is a point covered in 2 other talks at the conference (Practical Metaprogramming in Go and Embracing the Standard Library). func main() { flag.Parse() if len(*typeNames) == 0 { log.Fatalf("the flag -type must be set") } types := strings.Split(*typeNames, ",")

// Only one directory at a time can be processed, and the default is ".". dir := "." if args := flag.Args(); len(args) == 1 { dir = args[0] } else if len(args) > 1 { log.Fatalf("only one directory at a time") }

pkg, err := parser.ParsePackage(dir, *outputSuffix+".go") if err != nil { log.Fatalf("parsing package: %v", err) }

var analysis = struct { Command string PackageName string TypesAndValues map[string][]string }{ Command: strings.Join(os.Args[1:], " "), PackageName: pkg.Name, TypesAndValues: make(map[string][]string), }

// Run generate for each type. for _, typeName := range types { values, err := pkg.ValuesOfType(typeName) if err != nil { log.Fatalf("finding values for type %v: %v", typeName, err) } analysis.TypesAndValues[typeName] = values

var buf bytes.Buffer if err := generatedTmpl.Execute(&buf, analysis); err != nil { log.Fatalf("generating code: %v", err) }

src, err := format.Source(buf.Bytes()) if err != nil { // Should never happen, but can arise when developing this code. // The user can compile the output to see the error. log.Printf("warning: internal error: invalid Go generated: %s", err) log.Printf("warning: compile the package to analyze the error") src = buf.Bytes() }

output := strings.ToLower(typeName + *outputSuffix + ".go") outputPath := filepath.Join(dir, output) if err := ioutil.WriteFile(outputPath, src, 0644); err != nil { log.Fatalf("writing output: %s", err) } }} View in context func main in campoy/jsonenums on ✱ Sourcegraph An interactive snippet showing how the jsonenums command is written.

译者信息

go generate 现在来看看go generate。go generate是一个你可以用来自动自成Go代码的命令。你可以结合例如jsonenums(一个用于为枚举类型自动生成JSON编组样板代码的类库)这样的元编程来使用go generate快速自动实现重复乏味代码的编写。在Go标准类库里面已经有大量可以用于解析AST的接口,而AST使得编写元编程工具更简单,更容易。在会议上,有另外两次讨论(Go语言中的元编程实践和拥抱标准类库)谈及到了这一点。 func main() { flag.Parse() if len(*typeNames) == 0 { log.Fatalf("the flag -type must be set") } types := strings.Split(*typeNames, ",")

// Only one directory at a time can be processed, and the default is ".". dir := "." if args := flag.Args(); len(args) == 1 { dir = args[0] } else if len(args) > 1 { log.Fatalf("only one directory at a time") }

pkg, err := parser.ParsePackage(dir, *outputSuffix+".go") if err != nil { log.Fatalf("parsing package: %v", err) }

var analysis = struct { Command string PackageName string TypesAndValues map[string][]string }{ Command: strings.Join(os.Args[1:], " "), PackageName: pkg.Name, TypesAndValues: make(map[string][]string), }

// Run generate for each type. for _, typeName := range types { values, err := pkg.ValuesOfType(typeName) if err != nil { log.Fatalf("finding values for type %v: %v", typeName, err) } analysis.TypesAndValues[typeName] = values

var buf bytes.Buffer if err := generatedTmpl.Execute(&buf, analysis); err != nil { log.Fatalf("generating code: %v", err) }

src, err := format.Source(buf.Bytes()) if err != nil { // Should never happen, but can arise when developing this code. // The user can compile the output to see the error. log.Printf("warning: internal error: invalid Go generated: %s", err) log.Printf("warning: compile the package to analyze the error") src = buf.Bytes() }

output := strings.ToLower(typeName + *outputSuffix + ".go") outputPath := filepath.Join(dir, output) if err := ioutil.WriteFile(outputPath, src, 0644); err != nil { log.Fatalf("writing output: %s", err) } }} 查看上下文

✱ Sourcegraph 站点上 campoy/jsonenums 中的 main 函数

一段互动的片段演示了如何编写jsonenums命令。

OpenGL Many people use Go for web services, but did you know that you can also create cool graphics in Go? Check out the OpenGL bindings in Go. func main() { glfw.SetErrorCallback(errorCallback)

if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate()

window, err := glfw.CreateWindow(Width, Height, Title, nil, nil) if err != nil { panic(err) }

window.MakeContextCurrent()

glfw.SwapInterval(1)

gl.Init()

if err := initScene(); err != nil { fmt.Fprintf(os.Stderr, "init: %s\n", err) return } defer destroyScene()

for !window.ShouldClose() { drawScene() window.SwapBuffers() glfw.PollEvents() }} View in context func main in go-gl/examples on ✱ Sourcegraph Interactive snippet illustrating use of Go OpenGL bindings to make a Gopher cube. Click a function or method name to explore. Hackathons and challenges You should also check out challenges and hackathons like the Gopher Gala and the Go Challenge. In the past, programmers from around the world have hacked together some really cool projects that you can take inspiration from.

译者信息

OpenGL 许多人使用Go作web服务,但是你知道你也可以用Go写出很cool的图形应用吗?查看Go在OpenGL中的捆绑。 func main() { glfw.SetErrorCallback(errorCallback)

if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate()

window, err := glfw.CreateWindow(Width, Height, Title, nil, nil) if err != nil { panic(err) }

window.MakeContextCurrent()

glfw.SwapInterval(1)

gl.Init()

if err := initScene(); err != nil { fmt.Fprintf(os.Stderr, "init: %s\n", err) return } defer destroyScene()

for !window.ShouldClose() { drawScene() window.SwapBuffers() glfw.PollEvents() }} 在文本中查看 在 ✱ Sourcegraph中 go-gl/examples 里面的函数 main 交互式的片段正说明Go的OpenGL捆绑能制作Gopher cube。点击函数或方法名去探索。 黑客马拉松和挑战 你也可以观看挑战和黑客马拉松,类似Gopher Gala和Go Challenge。在过去,来自世界各地的程序员一起挑战一些真实的酷项目,你可以从中获取灵感。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接 我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们

  • 1

  • 2

GO 语言学习的五个阶段(带例子) 返回原文

英文原文:The 5 stages of learning Go (with examples)

Francesc (@francesc) is a member of the Go core team and a developer advocate for Google Cloud Platform. He’s a lover of programming languages, a master of technical instruction at Google, and one of the creators of the Go tour. This talk was inspired by another talk from Raquel Vélez at JSConf. Slides for this talk have been posted here. Sourcegraph is building the next generation of programming collaboration tools for searching, exploring, and reviewing code. We attended GopherCon India to share how we use Go and learn from how others are using it, and were honored to coordinate the liveblog of the talks.

译者信息 Francesc (@francesc) 是 Go 核心团队的一员, 是提倡 Google Cloud 平台的开发者. 他是一个编程语言的爱好者, Google的技术指导大师, Go tour的创造者之一. 这个讨论的灵感来自于另一个 Raquel Vélez 在 JSConf. Slides 的讨论,这个讨论已经发到了这里. Sourcegraph 是下一代编程协作工具, 用于搜索, 探索, 和审查代码. 我们参加GopherCon India 来分享我们是怎样使用 Go 并学习别人是怎样使用它的, 对配合liveblog的这次讨论我们深感荣幸.

As a developer advocate on the Go team, Francesc has probably interacted with more Go programmers than almost anyone else in the world. From this unique vantage point, he has seen 5 general stages in the evolution of programmers working in Go. These stages apply to how programmers progress through other languages, too. Understanding where you are in this evolution can help you figure out the most effective ways to improve and avoid common pitfalls that befall students of programming languages at every level. Editor’s note: this post has interactive code snippets for each phase of this evolution. Clicking on any function name jumps you to the definition in code for further exploration. Scroll down to see them.

译者信息 作为Go团队的开发者之一,Francesc可能比世界上其他人接触到的Go语言程序员都要多。正因为有了这样的有利条件,他把Go语言的学习过程划分为5个阶段。 这些阶段对于其他语言的学习也是成立的。理解自己处于哪个阶段,可以帮助你找到提高自己的最有效的方法,也可以避免每个阶段学习过程中的常见陷阱。 编者按:这篇文章对于每一个学习阶段都给出了交互式的代码片段。点击函数名你就可以跳到具体的函数定义,方便进行深入的研究。请看下文。

Here the 5 phases in the evolution of a Gopher:

  • Phase 1 (the newcomer): You just learned the language. You’ve gone through a few tutorials or workshops, you understand basic syntax, and you can write short snippets of code.
  • Phase 2 (the explorer): You can write a complete program, but don’t understand some more advanced language features like channels. You haven’t yet written a large project in Go.
  • Phase 3 (the builder): You’re proficient in Go, you’re using Go in production to solve a specific and complete problem. You have a strong command of the common patterns and idioms in the language community. Go is a strong tool in your programming toolbelt.
  • Phase 4 (the expert): You understand the design choices and motivations behind the language. You grok the philosophy of simplicity and composability.
  • The advocate: You’re actively sharing your knowledge and understanding of the language with others. You’re a voice in the community, a participant on mailing lists and chatrooms, and you’re giving talks at conferences. Being an advocate is not really a separate stage, but a role you can fill at any of the other stages.

译者信息 这里是GO程序员的五个进化阶段:

  • 第一个阶段(菜逼): 刚刚学习了这门语言。 已经通过一些教程或者培训班了解基本的语法,可以写短的代码片段。
  • 第二个阶段 (探索者): 可以写一个完整的程序,但不懂一些更高级的语言特征,比如“channels”。还没有使用GO写一个大项目。
  • 第三个阶段(大手): 你能熟练的使用Go, 能够用GO去解决,生产环境中一个具体和完整的问题。已经形成了一套自己的惯用法和常用代码库。在你的编码方案中Go是一个非常好用的工具。
  • 第四阶段 (大神): 绝逼清楚Go语言的设计选择和背后的动机。能理解的简洁和可组合性哲学。
  • 布道师: 积极地与他人分享关于Go语言知识和你对Go语言的理解。在各种合适的场所发出自己的声音, 参与邮件列表、建立QQ群、做专题报告。成为一个布道者不见得是一个完全独立的阶段,这个角色可以在上述的任何一个阶段中。

Phase 1: the newcomer Newcomers are at the stage where they’re creating small programs and toy projects in Go. They should take advantage of the Go tour, the Go playground, the docs, and the mailing list (golang-nuts). func main() { fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))} View in context func main in golang/example on ✱ Sourcegraph An interactive snippet from hello.go in the golang/example repository, which contains simple examples of small Go programs. Click around to explore the code.

译者信息

第一阶段: 菜逼 菜鸟在这个阶段使用Go去创建一些小项目或者玩具项目。他们应该会利用到Go tour, Go playground, Go文档, 和邮件列表(golang-nuts). func main() { fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))} 查看上下文

func main in golang/example on ✱ Sourcegraph

这是Go语言写的简单例子,这个代码段来自golang/example 代码库里面的 hello.go 。 点击就可以查看完整代码撸。

An important skill newcomers should develop is learning how to ask questions. A lot of people new to the mailing list say things like, “Hey, this doesn’t work,” without providing enough context to enable others to understand and help fix their problem. At the opposite end of the spectrum are those who copy and paste hundreds of lines of code into a forum post and haven’t invested the time to come up with a focused example that illustrates their problem. Also, you should rarely copy and paste code directly into the forum. Instead use the “share” button of the Go playground to link to snippets of code that others can edit and run directly in their browser.

译者信息 一项重要的技能,新人应该试着学习如何正确提问。很多新人在邮件列表里面这样说“嘿,这报错了”,这并没有提供足够的信息,让别人能理解并帮助他们解决问题。别人看到的是一个粘贴了几百行的代码的帖子,并没有花费精力来重点说明所遇到的问题。 所以, 应该尽量避免直接粘贴代码到论坛。而应该使用可以编辑并且可以在浏览器中直接运行的Go playground的“分享”按钮链接到代码片段。

Phase 2: the explorer The explorer has written some small projects in Go, but still gets lost sometimes. They might not fully understand or know how to use more advanced language features like channels. They still have many things to learn, but know enough to build useful things. They are starting to get a sense of the potential of Go and are excited about what they’ll be able to build in the language.

Within the explorer phase, you typically go through two steps. First, you ascend to the Peak of Inflated Expectations. You think you can do everything in Go, but without really understanding or grokking the Go ethos yet. You are probably trying to apply the idioms and patterns you know from other languages in Go code, and you don’t yet have a strong sense of what constitutes idiomatic Go. You try to undertake tasks like “migrate framework X from language Y to Go”.

译者信息

Phase 2: the explorer 探索者已经可以使用Go写一些小的软件,但有时仍然会有些迷茫。他们可能不完全明白怎么使用Go的高级特性,比如通道。虽然他们还有很多东西要学习,但已掌握的足够做一些有用的事情了!他们开始对Go的潜能有感觉了,并对它们能使用Go创建的东西感到兴奋。

在探索阶段通常会经历两个步骤。第一,膨胀的预期达到顶点,你觉得可以用Go做所有的事情,但还并不能明白或领悟到Go的真谛。你大概会用所熟悉的语言的模式和惯用语来写Go代码,但对于什么是地道的Go,还没有比较强烈的感觉。你开始尝试着手干这样的事情--“迁移架构X,从Y语言到Go语言”。

Following the Peak of Inflated Expectations is the Trough of Disillusionment. You miss feature X from language Y. You haven’t fully bought into idiomatic Go. You are still trying to write in the style of other programming languages and are getting frustrated. You may use the reflect and unsafe packages a lot. This is not idiomatic Go. Idiomatic Go tends to avoid things that are too “magical”. The Martini web framework is an example of a project that exemplifies the explorer phase. Martini was an early Go web framework that adopted a lot of concepts from Ruby web frameworks (like dependency injection). It received a lot of excitement from the community initially, but eventually had many issues around performance and debuggability. Jeremy Saenz (@codegangsta), the creator of Martini, responded constructively to feedback from the Go community and wrote another library called Negroni that follows more idiomatic Go conventions. func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed.

logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) logger.Fatalln(http.ListenAndServe(addr, m))} View in context (*Martini).RunOnAddr in go-martini/martini on ✱ Sourcegraph Interactive code snippet from the Martini web framework, an example of non-idiomatic Go. Note the dependency injection implemented via the reflect package. func TestNegroniServeHTTP(t *testing.T) { result := "" response := httptest.NewRecorder()

n := New() n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "foo" next(rw, r) result += "ban" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bar" next(rw, r) result += "baz" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bat" rw.WriteHeader(http.StatusBadRequest) }))

n.ServeHTTP(response, (*http.Request)(nil))

expect(t, result, "foobarbatbazban") expect(t, response.Code, http.StatusBadRequest)} View in context func TestNegroniServeHTTP in codegangsta/negroni on ✱ Sourcegraph Interactive code snippet demonstrating use of the Negroni library, an example of more idiomatic Go.

译者信息 到达预期膨胀的顶点之后,你会遇到理想幻灭的低谷。你开始想念语言Y的特性X,此时你还没有完全的掌握地道的Go。你还在用其他编程语言的风格来写Go语言的程序,你甚至开始觉得沮丧。你可能在大量使用reflect和unsafe这两个包,但这不是地道的Go。地道的Go不会使用那些魔法一样的东西。 这个探索阶段产生的项目的一个很好的例子就是Martini Web框架。Martini是一个Go语言的早期Web框架,它从Ruby的Web框架当中吸收了很多思想(比如依赖注入)。最初,这个框架在社区中引起了强烈的反响,但是它逐渐在性能和可调试性上受到了一些批评。Martini框架的作者Jeremy Saenz积极响应这些来自Go社区的反馈,写了一个更加符合Go语言规范的库Negroni

func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed.

logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) logger.Fatalln(http.ListenAndServe(addr, m))} 查看上下文

(*Martini).RunOnAddr in go-martini/martini on ✱ Sourcegraph

来自Martini框架的交互式代码片段,它是不地道的Go的例子。注意用反射包实现的依赖注入

func TestNegroniServeHTTP(t *testing.T) { result := "" response := httptest.NewRecorder()

n := New() n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "foo" next(rw, r) result += "ban" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bar" next(rw, r) result += "baz" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bat" rw.WriteHeader(http.StatusBadRequest) }))

n.ServeHTTP(response, (*http.Request)(nil))

expect(t, result, "foobarbatbazban") expect(t, response.Code, http.StatusBadRequest)} 查看上下文

func TestNegroniServeHTTP in codegangsta/negroni on * Sourcegraph

来自Negroni库的交互式代码片段,它是地道的Go的例子

Many other languages rely heavily on third-party libraries to deliver core functionality like HTTP handling. One thing that distinguishes Go is the power of its standard library. If you think the Go standard library is not powerful enough to do what you want to do, you might be wrong. The Go standard library is incredibly powerful, and it’s worth reading through its code to learn the patterns of how it implements things. func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})} View in context (*Server).ListenAndServe in golang/go on ✱ Sourcegraph An interactive snippet of the ListenAndServe method in the Go standard library. If you’ve written Go code, you’ve probably called this function many times, but have you bothered to see how it’s written? Go ahead and click around in the snippet above. The disillusionment of the Trough of Disillusionment comes from the fact that you are still thinking in the patterns of other languages and you haven’t yet fully explored much of what Go offers. Here are some fun things you can do to avoid stalling and dive further into cool things you can do in the language.

译者信息 其他语言在提供一些核心功能,比如HTTP处理的时候,往往需要依赖第三方库。但是Go语言在这一点上很不同,它的标准库非常强大。如果你认为Go标准库没有强大到可以做你想做的事情,那么我说你错了。Go语言标准库难以置信的强大,值得你花时间阅读它的代码,学习它实现的模式。 func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})} 在上下文中查看

(Server).ListenAndServe in golang/go on Sourcegraph

Go标准库中的ListenAndServe函数片段。如果你写过Go程序,你可能已经调用过这个函数很多次了,但是你曾经花时间看过它的实现么?去点击上面的代码片段吧。 幻灭的低谷中的幻灭感来自于这样的事实:你还在用其他语言的模式来想问题,而且你还没有完全探索过Go能提供给你什么。下面是一些好玩的事情,你可以做一下来打破困境,进一步探索这门语言中好玩的事。

go generate Check out go generate. go generate is a command that you can use to auto-generate Go code. You can use it in conjunction with metaprograms like jsonenums (a library to auto-generate JSON marshalling boilerplate code for enum types) to automate the writing of tedious code. The Go standard library has a great API for parsing the AST, which makes metaprogramming tools simple and easy to write. This is a point covered in 2 other talks at the conference (Practical Metaprogramming in Go and Embracing the Standard Library). func main() { flag.Parse() if len(*typeNames) == 0 { log.Fatalf("the flag -type must be set") } types := strings.Split(*typeNames, ",")

// Only one directory at a time can be processed, and the default is ".". dir := "." if args := flag.Args(); len(args) == 1 { dir = args[0] } else if len(args) > 1 { log.Fatalf("only one directory at a time") }

pkg, err := parser.ParsePackage(dir, *outputSuffix+".go") if err != nil { log.Fatalf("parsing package: %v", err) }

var analysis = struct { Command string PackageName string TypesAndValues map[string][]string }{ Command: strings.Join(os.Args[1:], " "), PackageName: pkg.Name, TypesAndValues: make(map[string][]string), }

// Run generate for each type. for _, typeName := range types { values, err := pkg.ValuesOfType(typeName) if err != nil { log.Fatalf("finding values for type %v: %v", typeName, err) } analysis.TypesAndValues[typeName] = values

var buf bytes.Buffer if err := generatedTmpl.Execute(&buf, analysis); err != nil { log.Fatalf("generating code: %v", err) }

src, err := format.Source(buf.Bytes()) if err != nil { // Should never happen, but can arise when developing this code. // The user can compile the output to see the error. log.Printf("warning: internal error: invalid Go generated: %s", err) log.Printf("warning: compile the package to analyze the error") src = buf.Bytes() }

output := strings.ToLower(typeName + *outputSuffix + ".go") outputPath := filepath.Join(dir, output) if err := ioutil.WriteFile(outputPath, src, 0644); err != nil { log.Fatalf("writing output: %s", err) } }} View in context func main in campoy/jsonenums on ✱ Sourcegraph An interactive snippet showing how the jsonenums command is written.

译者信息

go generate 现在来看看go generate。go generate是一个你可以用来自动自成Go代码的命令。你可以结合例如jsonenums(一个用于为枚举类型自动生成JSON编组样板代码的类库)这样的元编程来使用go generate快速自动实现重复乏味代码的编写。在Go标准类库里面已经有大量可以用于解析AST的接口,而AST使得编写元编程工具更简单,更容易。在会议上,有另外两次讨论(Go语言中的元编程实践和拥抱标准类库)谈及到了这一点。 func main() { flag.Parse() if len(*typeNames) == 0 { log.Fatalf("the flag -type must be set") } types := strings.Split(*typeNames, ",")

// Only one directory at a time can be processed, and the default is ".". dir := "." if args := flag.Args(); len(args) == 1 { dir = args[0] } else if len(args) > 1 { log.Fatalf("only one directory at a time") }

pkg, err := parser.ParsePackage(dir, *outputSuffix+".go") if err != nil { log.Fatalf("parsing package: %v", err) }

var analysis = struct { Command string PackageName string TypesAndValues map[string][]string }{ Command: strings.Join(os.Args[1:], " "), PackageName: pkg.Name, TypesAndValues: make(map[string][]string), }

// Run generate for each type. for _, typeName := range types { values, err := pkg.ValuesOfType(typeName) if err != nil { log.Fatalf("finding values for type %v: %v", typeName, err) } analysis.TypesAndValues[typeName] = values

var buf bytes.Buffer if err := generatedTmpl.Execute(&buf, analysis); err != nil { log.Fatalf("generating code: %v", err) }

src, err := format.Source(buf.Bytes()) if err != nil { // Should never happen, but can arise when developing this code. // The user can compile the output to see the error. log.Printf("warning: internal error: invalid Go generated: %s", err) log.Printf("warning: compile the package to analyze the error") src = buf.Bytes() }

output := strings.ToLower(typeName + *outputSuffix + ".go") outputPath := filepath.Join(dir, output) if err := ioutil.WriteFile(outputPath, src, 0644); err != nil { log.Fatalf("writing output: %s", err) } }} 查看上下文

✱ Sourcegraph 站点上 campoy/jsonenums 中的 main 函数

一段互动的片段演示了如何编写jsonenums命令。

OpenGL Many people use Go for web services, but did you know that you can also create cool graphics in Go? Check out the OpenGL bindings in Go. func main() { glfw.SetErrorCallback(errorCallback)

if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate()

window, err := glfw.CreateWindow(Width, Height, Title, nil, nil) if err != nil { panic(err) }

window.MakeContextCurrent()

glfw.SwapInterval(1)

gl.Init()

if err := initScene(); err != nil { fmt.Fprintf(os.Stderr, "init: %s\n", err) return } defer destroyScene()

for !window.ShouldClose() { drawScene() window.SwapBuffers() glfw.PollEvents() }} View in context func main in go-gl/examples on ✱ Sourcegraph Interactive snippet illustrating use of Go OpenGL bindings to make a Gopher cube. Click a function or method name to explore. Hackathons and challenges You should also check out challenges and hackathons like the Gopher Gala and the Go Challenge. In the past, programmers from around the world have hacked together some really cool projects that you can take inspiration from.

译者信息

OpenGL 许多人使用Go作web服务,但是你知道你也可以用Go写出很cool的图形应用吗?查看Go在OpenGL中的捆绑。 func main() { glfw.SetErrorCallback(errorCallback)

if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate()

window, err := glfw.CreateWindow(Width, Height, Title, nil, nil) if err != nil { panic(err) }

window.MakeContextCurrent()

glfw.SwapInterval(1)

gl.Init()

if err := initScene(); err != nil { fmt.Fprintf(os.Stderr, "init: %s\n", err) return } defer destroyScene()

for !window.ShouldClose() { drawScene() window.SwapBuffers() glfw.PollEvents() }} 在文本中查看 在 ✱ Sourcegraph中 go-gl/examples 里面的函数 main 交互式的片段正说明Go的OpenGL捆绑能制作Gopher cube。点击函数或方法名去探索。 黑客马拉松和挑战 你也可以观看挑战和黑客马拉松,类似Gopher Gala和Go Challenge。在过去,来自世界各地的程序员一起挑战一些真实的酷项目,你可以从中获取灵感。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接 我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

转载于:https://my.oschina.net/undermoonlightperson/blog/729242

go语言入门(转载自开源社区)相关推荐

  1. 开源社区应该选择什么语言?

    前传 在开源的世界里,应该讲开发者都能懂的语言!,这是李建盛的一篇博客,发在OSChina上,不过被很多人批评.我想还是需要完整的表达一下自己对于这个问题的看法,因此打算写一篇博客. 下篇 在我内心打 ...

  2. 开源社区的由来(转载)

    开源的含义 "开源社区"(Open Source Community)更准确的名称应该是"开源软件社区"(Open Source Software Commun ...

  3. 如何借助Vale减少开源社区文档中的负面和偏见语言

    ​ 整理 | 西狩xs   校对 | 山河已无恙 出品 | CSDN云原生 声明:本文出自CNCF,由技术作家Chris Ward在Chronosphere博客上发表.CSDN将文章翻译成中文,分享给 ...

  4. OpenHarmony开源社区快速入门(一)

    OpenHarmony开源社区快速入门(一) 本文主要介绍windows下基于命令行的方式搭建所需要的OpenHarmony开发环境: 开发环境准备 1.首先打开微软商店,搜索Ubuntu,下载ubu ...

  5. 【转】做一名开源社区的扫地僧 (上)

    不知道怎么为开源软件做贡献?从汇报 Bug 开始吧,或许还有钱赚呢- 且看 Qian Hong 的经验分享. 今年的软件自由日(SFD),我在广州Linux用户组的线下活动上做了一个分享,主题叫做&l ...

  6. 做一名开源社区的扫地僧——从Bug report到Google Summer of Code(GSoC):从200个bug到5000美金

    今年的软件自由日(SFD),我在广州Linux用户组的线下活动上做了一个分享,主题叫做<做一名开源社区的扫地僧(上)>.我把演讲的内容重新整理扩充, 写出了文字版, 希望可以跟更多朋友分享 ...

  7. 做一名开源社区的扫地僧

    不知道怎么为开源软件做贡献?从汇报 Bug 开始吧,或许还有钱赚呢- 且看 Qian Hong 的经验分享.全文转载开始 今年的软件自由日(SFD),我在广州Linux用户组的线下活动上做了一个分享, ...

  8. 500G !!史上最全的JAVA全套教学视频网盘分享 (JEECG开源社区)

    为什么80%的码农都做不了架构师?>>>    500 G JAVA视频网盘分享(JEECG开源社区) [涵盖从java入门到深入架构,Linux.云计算.分布式.大数据Hadoop ...

  9. 做一名开源社区扫地僧(转)

    2019独角兽企业重金招聘Python工程师标准>>> 今年的软件自由日(SFD), 我在广州Linux用户组的线下活动上做了一个分享, 主题叫做<<做一名开源社区的扫地 ...

  10. 做一名开源社区的扫地僧 (上)

    原载:LinuxTOY 作者:黑日白月 原文网址:http://linuxtoy.org/archives/from-bug-reporter-google-summer-code.html 不知道怎 ...

最新文章

  1. 2022-2028年中国微滤膜行业市场发展调研及投资前景分析报告
  2. 自定义present和dismiss的转场动画
  3. python中的urllib库_七、urllib库(一)
  4. ·MySQL数据库管理(SQL操作命令,解决忘记密码,设置用户权限)
  5. 快速配置 Samba 将 Linux 目录映射为 Windows 驱动器
  6. python的语句_Python的语句
  7. Docker cpu memory quota使用说明
  8. Linux执行source /etc/profile报错“:command not found”
  9. Vue+ElementUI 限制结束时间不能大于开始时间
  10. AWT:实现简单的java计算器
  11. 2020 CCPC 威海(赛后重现)
  12. CF1467C Three Bags(思维)
  13. 使用proteus仿真集成运放构成的三角波发生电路
  14. (附源码)springboot应用支撑平台和应用系统 毕业设计 984655
  15. 学员故事|老男孩网络安全学习感悟,结果让我意外!
  16. 四、PHP处理字符串常用函数
  17. suse日志服务器配置
  18. 对不起,我轻视了google的公关能力
  19. Vue视频流播放器 Vue-Core-Video-Player
  20. android 蒲公英 类似平台,Jenkins之android APP打包上传蒲公英平台

热门文章

  1. 2022年江苏省高职单招(数学)考试冲刺试题及答案
  2. matlab kappa风险分析,我为什么反对在属性数据MSA中用Kappa分析(上) | 汽车质量管理笔记...
  3. Inoventica干线网络,600 Gbit / s。
  4. 如何使用计算机来线性拟合,非线性数据拟合
  5. 进阶的阿牛哥之pandas透视表pivot_table的使用
  6. c++Windows怎样关机【详解】
  7. qt实现涂鸦板_Qt之旅--- 10 涂鸦板
  8. 施一公:如何写好一篇学术论文?
  9. ACM顽固错误之WA——常见掉坑点
  10. 小猪短租网requests库使用