{"action":"created","comment":{"url":"https://api.github.com/repos/studygolang/GCTT/pulls/comments/154420662","pull_request_review_id":80577671,"id":154420662,"diff_hunk":"@@ -0,0 +1,470 @@\n+﻿# Golang 对于 DevOps 之利弊(第 1 部分，共 6 部分)：Goroutines, Panics, and Errors  \n+![](https://camo.githubusercontent.com/92a4d1155a66df2b93aa537cff26837267f4952d/68747470733a2f2f626c6f672e626c75656d617461646f722e636f6d2f68756266732f426c75655f4d617461646f725f496e635f4f63746f626572323031372f496d616765732f676f6c616e672d70726f732d636f6e732d666f722d6465766f70732d706172742d312d676f726f7574696e65732d70616e6963732d6572726f72732e706e673f743d31353131323832353139383332)\n+\n+对于你的下一个 DevOps 应用来说，Google 公司的 Go 可能是完美的语言。作为由 6 篇组成一个系列文章的第一篇，我们从 goroutines, panics, and errors 开始深入研究 Go 语言的利与弊，因为这些利与弊涉及构建 DevOps 应用。      \n+在这篇博客中，我们已经称赞了 Google 公司的 Go 语言的优点，而且我们也写了[Go 迷你入门指南](https://blog.bluematador.com/posts/mini-guide-google-golang-why-its-perfect-for-devops/?utm_source=bm-blog&utm_medium=link&utm_campaign=golang-pros-cons-1)。 \n+但是以免任何人认为我们假借 DevOps 监控平台(我们是)的地下 Google 员工(我们不是)，我们更愿意去研究语言的利与弊，特别是当它涉及构建 DevOps 应用时。由于我们将智能代理(软件)从 Python(构建) 转换到 Go(构建)，我们有许多在 Go 语言环境下工作(开发)的经验，并且我们也有一些自认为很重要的东西(知识)来与更大的 DevOps 社区分享。    \n+从这周开始，我们将发布由 6 篇组成一系列关于 Go 语言利和弊文章，每一篇文章都详述了少许的内容。正如我们所做的，我们将通过链接到其它篇目来更新这篇文章：     \n+\n+- Golang 对于 DevOps 之利弊第一篇:Goroutines, Channels, Panics, and Errors(本篇)    \n+- [Golang 对于 DevOps 之利弊第二篇:自动接口实现，共有/私有变量](https://blog.bluematador.com/posts/golang-pros-cons-for-devops-part-2)   \n+- [Golang 对于 DevOps 之利弊第三篇:速度 VS 缺少泛型](https://blog.bluematador.com/posts/golang-pros-cons-devops-part-3-speed-lack-generics)   \n+- [Golang 对于 DevOps 之利弊第四篇:时间包与方法重载](https://github.com/studygolang/GCTT/blob/master/golang-pros-cons-part-4-time-package-method-overloading)   \n+- Golang 对于 DevOps 之利弊第五篇:交叉编译，窗口，信号，文档和编译器    \n+- Golang 对于 DevOps 之利弊第六篇:Defer 语句和包依赖版本控制    \n+如果本篇是你的有关 Go 的首次读物，并且你已经知道怎样用类 C 的语言进行编程，你应该去参考[Go 之旅](https://tour.golang.org/welcome/1)，它将大约花费你一个小时，而且(介绍)相当有深度。接下来的评论不是学习如何用 Go 进行编程的好方法。相反，它们(评论)只是我们在用 Go 开发智能代理(软件)时的怨言和我们发现的可取之处。   \n+准备好听一下用 Go 进行编程的真正样子吗？那我们开始吧。   \n+## Go 语言的好处 1: Goroutines — 轻量，内核级线程    \n+---    \n+Goroutines 等同于 Go。Goroutines 是执行线程，并且它们是轻量的和内核级的。轻量级是因为你可以在不影响系统性能的同时运行很多的 Goroutine，而内核级是因为它们并行运行(真正的并行运行，而不是像在其他语言中的伪并行，比如旧版的 Ruby)。同时也不像 Python那样，在 Go 中没有全局解释器锁(GIL)。    \n+换句话说，Goroutines 是 Go 语言中的重要部分，而不是后来才添加的特性，这正是 Go 语言执行之快的原因之一。另一方面，Java 有一个复杂的线程调度器。它们在为线程的执行创造条件，但是需要很多的管理工作，因此降低了你的程序运行速度。从另一个角度看，Node.js 没有真正的并发，仅仅是并发的假象。这是对于 DevOps 用途来说，Go 能成为一门伟大的语言的原因，它不影响你的系统性能，真正的并行执行，并且在意外的硬件故障中尽可能的可靠。     \n+### 怎样执行一个 Goroutine    \n+启动一个 Goroutine 线程超级简单。首先，你将在我们的看门狗产品中看到一些伪代码：   \n+```   \n+import \"time\"\n+func monitorCpu() { … }\n+func monitorDisk() { … }\n+func monitorNetwork() { … }\n+func monitorProcesses() { … }\n+func monitorIdentity() { … }\n+\n+func main() {\n+\tfor !shutdown {\n+\t\tmonitorCpu()\n+\t\tmonitorDisk()\n+\t\tmonitorNetwork()\n+\t\tmonitorProcesses()\n+\t\tmonitorIdentity()\n+\t\ttime.Sleep(5*time.Second)\n+\t}\n+}   \n+```     \n+在上面的代码中，CPU，硬盘，网络，进程和身份每 5 秒检查一次。如果上述其中之一挂掉的话，所有的监控就会终止。每一个监控用时越长，检查变得越不频繁，因为我们在计算完成之后需要睡眠 5 秒。(ps.最后一句没看懂)\n+为了解决这些问题，一种解决方案(一种不完整的方案，但是完美展示 goroutine 的价值所在)是使用 goroutine 来调用每一个监控函数。仅仅在你想要以线程方式产生的函数调用前加上 `go`关键字。     \n+```\n+func main() {\n+\tfor !shutdown {\n+\t\tgo monitorCpu()\n+\t\tgo monitorDisk()\n+\t\tgo monitorNetwork()\n+\t\tgo monitorProcesses()\n+\t\tgo monitorIdentity()\n+\t\ttime.Sleep(5*time.Second)\n+\t}\n+}   \n+```\n+现在如果它们之中任何一个挂掉的话，仅仅被阻塞的调用会被终止，不会阻塞其它的监控调用函数。并且因为产生一个线程很容易也很快，现在我们事实上更靠近了每隔 5 秒钟检查这些系统。     \n+当然，上述这个解决方案也有其他问题，比如在一个 goroutine 的 panic 可能会破坏其他 goroutine，睡眠时间有少量的偏差，代码并不像看到的那样模块化等等。但是生成内核级线程不是很容易吗？    \n+正如你所看到的，Java 程序需要 12 行代码，而 Go 却只需要 2 个单词。我们想说这意味着你的 Go 源代码将变得简洁和紧凑，但是当我们在这篇文章之后介绍的 panics 和 errors 时，你将会看到不幸的是并非如此(事实上 Go 语言是一种比较臃肿的语言，现在信不信由你)。    \n+### 同步包(和 Channels)加上编配    \n+我们使用 Go 的同步包和 channels 是为了 goroutine 的编配，发送信号和关机。你将会发现对 sync.Mutex 和 sync.WaitGroup 的引用以及一种称为 shutdownChannel 的重复的结构体变量充斥在我们的代码中。    \n+在 [Go manual](https://golang.org/pkg/sync/) 中关于 sync.Mutex 和 sync.WaitGroup 有一个重要的提示:    \n+>> 不应拷贝包含此包中定义的类型的值。      \n+\n+解释给那些整天不使用 Go，C 或者 C++ 的人(ps.拿不准):结构体是值传递的(ps.感觉应该是引用传递)。任何时间你创建一个 Mutex 或者 WaitGroup，使用一个指针，不要使用直接的值。这并不是普遍必需的，但是如果你不知道何时是好是坏，请一直使用指针。这里有一个很好的，简单的例子:    \n+```\n+type Example struct {\n+\twg *sync.WaitGroup\n+\tm *sync.Mutex\n+}\n+\n+func main() {\n+\twg := &sync.WaitGroup{}\n+\tm := &sync.Mutex{}\n+}   \n+```   \n+然而对于这些结构体的警告恰恰在页面的顶部，很容易掩饰过去，将会导致你将要构建的应用出现奇怪的副作用。   \n+从前一节关于监控的那个例子来看，这个例子是我们如何使用一个 WaitGroup 来确保在任何时候每个系统中不会有多于一个的监控:   \n+```\n+import \"sync\"\n+…\n+func main() {\n+\tfor !shutdown {\n+\t\twg := &sync.WaitGroup{}\n+\n+\t\tdoCall := func(fn func()) {\n+\t\t\twg.Add(1)\n+\t\t\tgo func() {\n+\t\t\t\tdefer wg.Done()\n+\t\t\t\tfn()\n+\t\t\t}\n+\t\t}\n+\n+\t\tdoCall(monitorCpu)\n+\t\tdoCall(monitorDisk)\n+\t\tdoCall(monitorNetwork)\n+\t\tdoCall(monitorProcesses)\n+\t\tdoCall(monitorIdentity)\n+\n+\t\twg.Wait()\n+\t}\n+}   \n+```    \n+一个 mutex 是保护共享资源的好方法，比如服务器上的CPU度量历史，正在监视日志文件的水印，或对更新事件感兴趣的监听器列表。这里没有惊奇的地方，除了一个相当令人可怕的 `defer` 关键字外，但是它超出这篇文章的范畴了。   \n+``` \n+package main\n+\n+import (\n+\t\"fmt\"\n+\t\"sync\"\n+\t\"time\"\n+)\n+\n+func printAndSleep(m *sync.Mutex, x int) {\n+\tm.Lock()\n+\tdefer m.Unlock()\n+\tfmt.Println(x)\n+\ttime.Sleep(time.Second)\n+}\n+\n+func main() {\n+\tm := &sync.Mutex{}\n+\tfor i := 0; i < 10; i++ {\n+\t\tprintAndSleep(m, i)\n+\t}\n+}   \n+```    \n+goroutine(s) 不仅容易启动，而且总的来说它们也容易协调，关闭和等待。不过有几个复杂的事情要处理，它们可能会更加深入一些:对多线程的事件广播，工作池，还有分布式处理。   \n+### Goroutines 的自动清理      \n+goroutine(s) 持有堆变量和栈变量的引用(避免垃圾收集)，但是并不需要一直持有这些引用。它们(goroutines)一直运行直到函数完成，然后关闭并且自动释放所有资源。在这个过程中有一个需要注意的部分是如果主线程已经退出，启动一个 goroutine 会被忽略(或者跳过)。 \n+首先，这里举一个有关启动 goroutine 并被忽略的真实例子。在我们的应用中，我们在子进程中启动一个模块(函数)，并且使用 IPC 来配置更新，设置更新和心跳。父进程和每个模块进程(子进程)必须不断地从 IPC channel 中读取数据，并且彼此向对方发送数据。这是一种我们启动并且忽略的线程，因为我们不关心如果(对方已经)关闭，我们不能读取完整的流。请持保留态度的看这段代码，虽然它来自我们的代码，但是为了简单起见，移除了一些重量级的代码:   \n+```\n+package ipc\n+\n+import (\n+\t\"bufio\"\n+\t\"bytes\"\n+\t\"fmt\"\n+\t\"os\"\n+\t\"time\"\n+)\n+\n+type ProtocolReader struct {\n+\tChannel chan *ProtocolMessage\n+\treader  *bufio.Reader\n+\thandle  *os.File\n+}\n+\n+func NewProtocolReader(handle *os.File) *ProtocolReader {\n+\treturn &ProtocolReader{\n+\t\tmake(chan *ProtocolMessage, 15),\n+\t\tbufio.NewReader(handle),\n+\t\thandle,\n+\t}\n+}\n+\n+func (this *ProtocolReader) ReadAsync() {\n+\tgo func() {\n+\t\tfor {\n+\t\t\tline, err := this.reader.ReadBytes('\\n')\n+\t\t\tif err != nil {\n+\t\t\t\tthis.handle.Close()\n+\t\t\t\tclose(this.Channel)\n+\t\t\t\treturn nil\n+\t\t\t}\n+\n+\t\t\tmessage := &ProtocolMessage{}\n+\t\t\tmessage.Unmarshal(line)\n+\t\t\tthis.Channel <- message\n+\t\t}\n+\n+\t\treturn nil\n+\t}\n+}\n+```      \n+第二个例子用来说明主线程退出而忽略正在运行的 goroutine:   \n+```\n+package main\n+\n+import (\n+\t\"fmt\"\n+\t\"time\"\n+)\n+\n+func waitAndPrint() {\n+\ttime.Sleep(time.Second)\n+\tfmt.Println(\"got it!\")\n+}\n+\n+func main() {\n+\tgo waitAndPrint()\n+}  \n+```   \n+使用 `sync.WaitGroup` 很容易修复这个问题。你将会看到很多像这个代码示例一样使用 time.Sleep 用来等待的例子。如果你助长了这种疯狂(使用 time.Sleep)，我们确实会小看你的。请使用 WaitGroup 来写代码吧。     \n+### Channels      \n+Go 语言的 channel(s) 是很好的单向消息传递工具。我们在代理软件中使用它们用于消息传递，消息广播和工作队列。它们会被 GC 自动清理，不需要(手动)关闭，并且很容易生成：  \n+```\n+numSlots := 5\n+make(chan int, numSlots)   \n+```   \n+你可以通过这个 channel 传送任何一种目标。你可以让它们同步工作，异步工作，或者让多个读端来监听这些 channels，并做具体的一些工作。    \n+不像 queue，一个 channel 可以被用来广播一个消息。在我们的代码中，最经常用来广播的消息是关闭。当到了关闭时刻，我们向所有后台 goroutines 发送广播:到清理空间的时间了。使用一个 channel 向多个监听者发送单一消息仅仅只有一种方式，那就是你必须关闭这个 channel。下面是我们代码的简化版本:    \n+```    \n+package main\n+\n+import (\n+\t\"fmt\"\n+\t\"sync\"\n+\t\"time\"\n+)\n+\n+var shutdownChannel = make(chan struct{}, 0)\n+var wg = &sync.WaitGroup{}\n+\n+func start() {\n+\twg.Add(1)\n+\tgo func() {\n+\t\tticker := time.Tick(100*time.Millisecond)\n+\n+\t\tfor shutdown := false; !shutdown; {\n+\t\t\tselect {\n+\t\t\tcase <-ticker:\n+\t\t\t\tfmt.Println(\"tick\")\n+\t\t\tcase <-shutdownChannel:\n+\t\t\t\tfmt.Println(\"tock\")\n+\t\t\t\tshutdown = true\n+\t\t\t}\n+\t\t}\n+\t\twg.Done()\n+\t}()\n+}\n+\n+func stop() {\n+\tclose(shutdownChannel)\n+}\n+\n+func wait() {\n+\twg.Wait()\n+}\n+\n+func main() {\n+\tstart()\n+\ttime.Sleep(time.Second)\n+\tstop()\n+\twait()\n+}    \n+```    \n+我们对 Go 中的 `select` 功能情有独钟。它允许我们在做重要工作的同时可以响应中断。我们可以相当自由的使用它来管理关闭信号和定时器(像上例那样)，读取多个数据流，并且可以和 Go 的 [fsnotify](https://github.com/fsnotify/fsnotify) 一起使用。   \n+## Go 语言的糟糕之处 1:Panic 和 error 的处理      \n+panic 和 error,它们是 Go 语言中最糟糕的东西，绝对是最糟糕的东西(ps.long shot?)。首先，让我们来为 panic 和 error 来下个定义，因为并不是每一门编程语言都会处理它们。     \n+根据 [Go 官方博客的一篇文章](https://blog.golang.org/defer-panic-and-recover)，      \n+>> panic 是一个终止普通控制流并且开始产生一个 panic 的內建函数。当函数 F 引发 panic 时，F 的执行终止，通常函数 F 中的任一 deferred 函数会被执行，并且 F 会返回它的调用者。对于调用者来说，F 表现的像一个对 panic 调用的函数。这个进程继续收回栈帧(栈是向下增长，函数返回时退栈)直到当前 goroutine 中所有的函数返回，这时程序就崩溃了。Panics 可以通过直接调用来引发。它们也可以由运行时错误如数组访问越界所引发。   \n+\n+换句话说，当你遇到一个控制流问题时，panics 终止你的程序。    \n+有几种方式可以触发一个 panic:    \n+- 调用函数来引发 panic   \n+- 除 0     \n+- 关闭一个已经关闭的 channel   \n+- 映射不存在的属性，比如 `Attribute = map[\"This doesn’t exist\"]`   \n+\n+另一方面，error 是一个內建类型，这种类型表示能自声明为字符串类型的值。这是从 Go 源代码引用的定义:    \n+```\n+type error interface {\n+\tError() string\n+}\n+```\n+根据以上定义，这是对于为什么我们讨厌 Go 拥有 error 和 panic 的总结:    \n+#### Error 是为了避免异常流，而 panic 抵消了这种作用\n+对于任何一种编程语言，只要拥有 error 和 panic 其中之一就足够了。一些编程语言选择二者兼有是令人沮丧的，至少可以这么说。Go 开发者们跟随着那些选择二者兼有的错误的设计者们，不幸的放弃了他们的命运。(ps.拿不准)     \n+### 一份在流行编程语言中错误处理的抽样     \n+<table>\n+<tbody>\n+<tr>\n+<td>Golang</td>\n+<td>panic(实际上更像 error)，exceptions & segfault</td>\n+</tr>\n+<tr>\n+<td>Java</td>\n+<td>exceptions</td>\n+</tr>\n+</tr>\n+<tr>\n+<td>Scala</td>\n+<td>exceptions</td>\n+</tr>\n+</tr>\n+<tr>\n+<td>Ruby</td>\n+<td>error(实际上更像 exceptions)</td>\n+</tr>\n+</tr>\n+<tr>\n+<td>Python</td>\n+<td>exceptions</td>\n+</tr>\n+<tr>\n+<td>PHP</td>\n+<td>error & exceptions</td>\n+</tr>\n+<tr>\n+<td>Javascript</td>\n+<td>exceptions</td>\n+</tr>\n+<tr>\n+<td>C/C++</td>\n+<td>error,exceptions & segfault</td>\n+</tr>\n+<tr>\n+<td>Objective-C</td>\n+<td>exceptions & error</td>\n+</tr>\n+<tr>\n+<td>Swift</td>\n+<td>error</td>\n+</tr>\n+</tbody>\n+</table>\n+总有可能返回错误，但对语言来说可能并不必要。Go 的內建函数支持访问 map 元素，从 channel 中读取数据，JSON 编码，并且也更需要错误处理。这就使为什么 Go 和 其他一些类似的语言接纳 \"error\"这个设计，而像 Python 和 Scala 等语言却没有。   \n+[Go 的官方博客](https://blog.golang.org/error-handling-and-go)再次介绍:    ","path":"translated/tech/201711 Golang Pros and Cons for DevOps/Goroutines, Panics, and Errors.md","position":318,"original_position":318,"commit_id":"67e2ae7fcb9c1addc31f70be5d64b8c76f908926","original_commit_id":"67e2ae7fcb9c1addc31f70be5d64b8c76f908926","user":{"login":"rxcai","id":5463519,"avatar_url":"https://avatars1.githubusercontent.com/u/5463519?v=4","gravatar_id":"","url":"https://api.github.com/users/rxcai","html_url":"https://github.com/rxcai","followers_url":"https://api.github.com/users/rxcai/followers","following_url":"https://api.github.com/users/rxcai/following{/other_user}","gists_url":"https://api.github.com/users/rxcai/gists{/gist_id}","starred_url":"https://api.github.com/users/rxcai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rxcai/subscriptions","organizations_url":"https://api.github.com/users/rxcai/orgs","repos_url":"https://api.github.com/users/rxcai/repos","events_url":"https://api.github.com/users/rxcai/events{/privacy}","received_events_url":"https://api.github.com/users/rxcai/received_events","type":"User","site_admin":false},"body":"这里个人觉得翻译为：\r\n还是来自 [Go 语言官方博客](https://blog.golang.org/error-handling-and-go) 的介绍\r\n更加自然","created_at":"2017-12-01T18:56:03Z","updated_at":"2017-12-01T19:02:45Z","html_url":"https://github.com/studygolang/GCTT/pull/71#discussion_r154420662","pull_request_url":"https://api.github.com/repos/studygolang/GCTT/pulls/71","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/comments/154420662"},"html":{"href":"https://github.com/studygolang/GCTT/pull/71#discussion_r154420662"},"pull_request":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/71"}}},"pull_request":{"url":"https://api.github.com/repos/studygolang/GCTT/pulls/71","id":154848176,"html_url":"https://github.com/studygolang/GCTT/pull/71","diff_url":"https://github.com/studygolang/GCTT/pull/71.diff","patch_url":"https://github.com/studygolang/GCTT/pull/71.patch","issue_url":"https://api.github.com/repos/studygolang/GCTT/issues/71","number":71,"state":"open","locked":false,"title":"完成翻译 201711 Golang Pros and Cons for DevOps/20170530 Part 1 Goroutines, Panics, and Errors.md","user":{"login":"liuxinyu123","id":16407853,"avatar_url":"https://avatars3.githubusercontent.com/u/16407853?v=4","gravatar_id":"","url":"https://api.github.com/users/liuxinyu123","html_url":"https://github.com/liuxinyu123","followers_url":"https://api.github.com/users/liuxinyu123/followers","following_url":"https://api.github.com/users/liuxinyu123/following{/other_user}","gists_url":"https://api.github.com/users/liuxinyu123/gists{/gist_id}","starred_url":"https://api.github.com/users/liuxinyu123/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/liuxinyu123/subscriptions","organizations_url":"https://api.github.com/users/liuxinyu123/orgs","repos_url":"https://api.github.com/users/liuxinyu123/repos","events_url":"https://api.github.com/users/liuxinyu123/events{/privacy}","received_events_url":"https://api.github.com/users/liuxinyu123/received_events","type":"User","site_admin":false},"body":"完成翻译 Goroutines, Panics, and Errors.md","created_at":"2017-11-27T16:02:18Z","updated_at":"2017-12-01T19:02:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"053dc3ba9771b386ca00f04c6e0cb7b4176d4fd9","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/studygolang/GCTT/pulls/71/commits","review_comments_url":"https://api.github.com/repos/studygolang/GCTT/pulls/71/comments","review_comment_url":"https://api.github.com/repos/studygolang/GCTT/pulls/comments{/number}","comments_url":"https://api.github.com/repos/studygolang/GCTT/issues/71/comments","statuses_url":"https://api.github.com/repos/studygolang/GCTT/statuses/67e2ae7fcb9c1addc31f70be5d64b8c76f908926","head":{"label":"liuxinyu123:master","ref":"master","sha":"67e2ae7fcb9c1addc31f70be5d64b8c76f908926","user":{"login":"liuxinyu123","id":16407853,"avatar_url":"https://avatars3.githubusercontent.com/u/16407853?v=4","gravatar_id":"","url":"https://api.github.com/users/liuxinyu123","html_url":"https://github.com/liuxinyu123","followers_url":"https://api.github.com/users/liuxinyu123/followers","following_url":"https://api.github.com/users/liuxinyu123/following{/other_user}","gists_url":"https://api.github.com/users/liuxinyu123/gists{/gist_id}","starred_url":"https://api.github.com/users/liuxinyu123/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/liuxinyu123/subscriptions","organizations_url":"https://api.github.com/users/liuxinyu123/orgs","repos_url":"https://api.github.com/users/liuxinyu123/repos","events_url":"https://api.github.com/users/liuxinyu123/events{/privacy}","received_events_url":"https://api.github.com/users/liuxinyu123/received_events","type":"User","site_admin":false},"repo":{"id":111539966,"name":"GCTT","full_name":"liuxinyu123/GCTT","owner":{"login":"liuxinyu123","id":16407853,"avatar_url":"https://avatars3.githubusercontent.com/u/16407853?v=4","gravatar_id":"","url":"https://api.github.com/users/liuxinyu123","html_url":"https://github.com/liuxinyu123","followers_url":"https://api.github.com/users/liuxinyu123/followers","following_url":"https://api.github.com/users/liuxinyu123/following{/other_user}","gists_url":"https://api.github.com/users/liuxinyu123/gists{/gist_id}","starred_url":"https://api.github.com/users/liuxinyu123/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/liuxinyu123/subscriptions","organizations_url":"https://api.github.com/users/liuxinyu123/orgs","repos_url":"https://api.github.com/users/liuxinyu123/repos","events_url":"https://api.github.com/users/liuxinyu123/events{/privacy}","received_events_url":"https://api.github.com/users/liuxinyu123/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/liuxinyu123/GCTT","description":"GCTT Go中文网翻译组。","fork":true,"url":"https://api.github.com/repos/liuxinyu123/GCTT","forks_url":"https://api.github.com/repos/liuxinyu123/GCTT/forks","keys_url":"https://api.github.com/repos/liuxinyu123/GCTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/liuxinyu123/GCTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/liuxinyu123/GCTT/teams","hooks_url":"https://api.github.com/repos/liuxinyu123/GCTT/hooks","issue_events_url":"https://api.github.com/repos/liuxinyu123/GCTT/issues/events{/number}","events_url":"https://api.github.com/repos/liuxinyu123/GCTT/events","assignees_url":"https://api.github.com/repos/liuxinyu123/GCTT/assignees{/user}","branches_url":"https://api.github.com/repos/liuxinyu123/GCTT/branches{/branch}","tags_url":"https://api.github.com/repos/liuxinyu123/GCTT/tags","blobs_url":"https://api.github.com/repos/liuxinyu123/GCTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/liuxinyu123/GCTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/liuxinyu123/GCTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/liuxinyu123/GCTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/liuxinyu123/GCTT/statuses/{sha}","languages_url":"https://api.github.com/repos/liuxinyu123/GCTT/languages","stargazers_url":"https://api.github.com/repos/liuxinyu123/GCTT/stargazers","contributors_url":"https://api.github.com/repos/liuxinyu123/GCTT/contributors","subscribers_url":"https://api.github.com/repos/liuxinyu123/GCTT/subscribers","subscription_url":"https://api.github.com/repos/liuxinyu123/GCTT/subscription","commits_url":"https://api.github.com/repos/liuxinyu123/GCTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/liuxinyu123/GCTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/liuxinyu123/GCTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/liuxinyu123/GCTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/liuxinyu123/GCTT/contents/{+path}","compare_url":"https://api.github.com/repos/liuxinyu123/GCTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/liuxinyu123/GCTT/merges","archive_url":"https://api.github.com/repos/liuxinyu123/GCTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/liuxinyu123/GCTT/downloads","issues_url":"https://api.github.com/repos/liuxinyu123/GCTT/issues{/number}","pulls_url":"https://api.github.com/repos/liuxinyu123/GCTT/pulls{/number}","milestones_url":"https://api.github.com/repos/liuxinyu123/GCTT/milestones{/number}","notifications_url":"https://api.github.com/repos/liuxinyu123/GCTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/liuxinyu123/GCTT/labels{/name}","releases_url":"https://api.github.com/repos/liuxinyu123/GCTT/releases{/id}","deployments_url":"https://api.github.com/repos/liuxinyu123/GCTT/deployments","created_at":"2017-11-21T11:27:09Z","updated_at":"2017-11-23T06:42:45Z","pushed_at":"2017-11-29T16:24:59Z","git_url":"git://github.com/liuxinyu123/GCTT.git","ssh_url":"git@github.com:liuxinyu123/GCTT.git","clone_url":"https://github.com/liuxinyu123/GCTT.git","svn_url":"https://github.com/liuxinyu123/GCTT","homepage":"https://studygolang.com/gctt","size":3351,"stargazers_count":0,"watchers_count":0,"language":"Shell","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"studygolang:master","ref":"master","sha":"2e7b5a742747ca7e084cce017101bdda6591d844","user":{"login":"studygolang","id":3772217,"avatar_url":"https://avatars3.githubusercontent.com/u/3772217?v=4","gravatar_id":"","url":"https://api.github.com/users/studygolang","html_url":"https://github.com/studygolang","followers_url":"https://api.github.com/users/studygolang/followers","following_url":"https://api.github.com/users/studygolang/following{/other_user}","gists_url":"https://api.github.com/users/studygolang/gists{/gist_id}","starred_url":"https://api.github.com/users/studygolang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/studygolang/subscriptions","organizations_url":"https://api.github.com/users/studygolang/orgs","repos_url":"https://api.github.com/users/studygolang/repos","events_url":"https://api.github.com/users/studygolang/events{/privacy}","received_events_url":"https://api.github.com/users/studygolang/received_events","type":"Organization","site_admin":false},"repo":{"id":110936509,"name":"GCTT","full_name":"studygolang/GCTT","owner":{"login":"studygolang","id":3772217,"avatar_url":"https://avatars3.githubusercontent.com/u/3772217?v=4","gravatar_id":"","url":"https://api.github.com/users/studygolang","html_url":"https://github.com/studygolang","followers_url":"https://api.github.com/users/studygolang/followers","following_url":"https://api.github.com/users/studygolang/following{/other_user}","gists_url":"https://api.github.com/users/studygolang/gists{/gist_id}","starred_url":"https://api.github.com/users/studygolang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/studygolang/subscriptions","organizations_url":"https://api.github.com/users/studygolang/orgs","repos_url":"https://api.github.com/users/studygolang/repos","events_url":"https://api.github.com/users/studygolang/events{/privacy}","received_events_url":"https://api.github.com/users/studygolang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/studygolang/GCTT","description":"GCTT Go中文网翻译组。","fork":false,"url":"https://api.github.com/repos/studygolang/GCTT","forks_url":"https://api.github.com/repos/studygolang/GCTT/forks","keys_url":"https://api.github.com/repos/studygolang/GCTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/studygolang/GCTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/studygolang/GCTT/teams","hooks_url":"https://api.github.com/repos/studygolang/GCTT/hooks","issue_events_url":"https://api.github.com/repos/studygolang/GCTT/issues/events{/number}","events_url":"https://api.github.com/repos/studygolang/GCTT/events","assignees_url":"https://api.github.com/repos/studygolang/GCTT/assignees{/user}","branches_url":"https://api.github.com/repos/studygolang/GCTT/branches{/branch}","tags_url":"https://api.github.com/repos/studygolang/GCTT/tags","blobs_url":"https://api.github.com/repos/studygolang/GCTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/studygolang/GCTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/studygolang/GCTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/studygolang/GCTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/studygolang/GCTT/statuses/{sha}","languages_url":"https://api.github.com/repos/studygolang/GCTT/languages","stargazers_url":"https://api.github.com/repos/studygolang/GCTT/stargazers","contributors_url":"https://api.github.com/repos/studygolang/GCTT/contributors","subscribers_url":"https://api.github.com/repos/studygolang/GCTT/subscribers","subscription_url":"https://api.github.com/repos/studygolang/GCTT/subscription","commits_url":"https://api.github.com/repos/studygolang/GCTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/studygolang/GCTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/studygolang/GCTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/studygolang/GCTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/studygolang/GCTT/contents/{+path}","compare_url":"https://api.github.com/repos/studygolang/GCTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/studygolang/GCTT/merges","archive_url":"https://api.github.com/repos/studygolang/GCTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/studygolang/GCTT/downloads","issues_url":"https://api.github.com/repos/studygolang/GCTT/issues{/number}","pulls_url":"https://api.github.com/repos/studygolang/GCTT/pulls{/number}","milestones_url":"https://api.github.com/repos/studygolang/GCTT/milestones{/number}","notifications_url":"https://api.github.com/repos/studygolang/GCTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/studygolang/GCTT/labels{/name}","releases_url":"https://api.github.com/repos/studygolang/GCTT/releases{/id}","deployments_url":"https://api.github.com/repos/studygolang/GCTT/deployments","created_at":"2017-11-16T07:10:44Z","updated_at":"2017-12-01T15:49:10Z","pushed_at":"2017-12-01T17:20:55Z","git_url":"git://github.com/studygolang/GCTT.git","ssh_url":"git@github.com:studygolang/GCTT.git","clone_url":"https://github.com/studygolang/GCTT.git","svn_url":"https://github.com/studygolang/GCTT","homepage":"https://studygolang.com/gctt","size":3421,"stargazers_count":135,"watchers_count":135,"language":"Shell","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":58,"mirror_url":null,"archived":false,"open_issues_count":10,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":58,"open_issues":10,"watchers":135,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/71"},"html":{"href":"https://github.com/studygolang/GCTT/pull/71"},"issue":{"href":"https://api.github.com/repos/studygolang/GCTT/issues/71"},"comments":{"href":"https://api.github.com/repos/studygolang/GCTT/issues/71/comments"},"review_comments":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/71/comments"},"review_comment":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/71/commits"},"statuses":{"href":"https://api.github.com/repos/studygolang/GCTT/statuses/67e2ae7fcb9c1addc31f70be5d64b8c76f908926"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"rxcai"}}