摘要:本文从 Go 的语法,类型零碎,编码格调,语言工具,编码工具和应用案例等几方面对 Go 语言进行了学习和探讨。
Go 语言公布之后,很多公司特地是云厂商也开始用 Go 语言重构产品的基础架构,而且很多企业都是间接采纳 Go 语言进行开发,最近热气腾腾的 Docker 就是采纳 Go 语言进行开发的。本文咱们一起来探讨和学习一下 Go 语言的技术特点。先来看个例子:
package main
import (
"fmt"
"time"
)
// 要在 goroutine 中运行的函数。done 通道将被用来告诉工作曾经实现。func worker(done chan bool) {fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
// 告诉实现。done <- true
}
func main() {
// 创立一个通道
done := make(chan bool, 1)
go worker(done)
// 期待 done 变为 true
<-done
}
上例中是一个在 Go 语言中应用 goroutine 和通道的例子。其中:
go 关键字是用来启动一个 goroutine
done <- true, 向通道传值
<-done,读取通道值
一、【概述】
Go 是由 RobertGriesemer、RobPike 和 KenThompson 在 Google 设计的一种动态类型化的、须编译后能力运行的编程语言。
Go 在语法上相似于 C 语言,但它具备 C 语言没有的劣势,如内存平安、垃圾回收、结构化的类型和 CSP 格调的并发性。
它的域名是 http://golang.org,所以通常被称为 ”Golang”,但正确的名称是 Go。
二、【GO 的设计思维】
Go 的设计受 C 语言的影响,但更加简略和平安。该语言包含如下特点:
- 采纳动静语言中比拟常见的语法和环境模式:
- 可选的扼要变量申明和通过类型推理进行初始化(如果应用 x := 0 而不是 int x= 0; 或 var x= 0;)。
- 疾速编译。
- 近程包治理 (go get) 和在线包文档。
- 针对特定问题的独特办法:
- 内置的并发基元:轻量级解决机制(goroutines)、通道和 select 语句。
- 用接口零碎代替虚构继承,用类型嵌入代替非虚构继承。
- 默认状况下,由一个工具链生成动态链接的原生二进制文件,没有内部依赖关系。
- 心愿放弃语言标准足够简略,程序员容易把握。
2.1 简洁的语法
Go 的语法蕴含 C 语言中放弃代码简洁性和可读性的语法特点。
2.1.1 变量申明
引入了一个联合声明 / 初始化操作符,容许程序员写出 i := 3 或 s :=”Hello, world!”,而不须要指定应用的变量类型。
这与 C 语言中的 int i= 3; 和 const char *s = “Hello, world!”; 造成鲜明对比。
2.1.2 分号隐含
分号依然是终止语句,但在行完结时是隐含的。
2.1.3 返回多值
在 Go 中,一个函数办法能够返回多个值,返回一个后果和谬误 err 组合对是向调用者提醒谬误的惯例形式。
2.1.4 范畴表达式
Go 的范畴表达式容许在数组、动静数组、字符串、字典和通道上进行简洁的迭代,在 C 语言中,有三种循环来实现这个性能。
2.2 类型零碎
2.2.1 内置的类型
Go 有许多内置的类型,包含数字类型(byte、int64、float32 等)、booleans 和字符串(string)。
字符串是不可更改的。
内置的运算符和关键字(而不是函数)提供了串联、比拟和 UTF- 8 编码 / 解码。
2.2.2 构造类型
记录类型能够用 struct 关键字定义。
2.2.3 数组类型
对于每个类型 T 和每个非负整数常数 n,都有一个数组类型,示意为[n]T,因而,不同长度的数组有不同的类型。
动静数组能够作为 ”Slice” 应用,如对于某类型 T,示意为[]T。这些数组有一个长度和一个容量,容量规定了何时须要调配新的内存来扩大数组。若干个 Slice 能够共享它们的底层内存。
2.2.4 指针
所有类型都能够定义指针,T 类型的指针可定义为 T。地址抽取和隐式拜访应用 & 和 操作符,这跟 C 语言一样,或者隐式的通过办法调用或属性拜访应用。
除了规范库中的非凡的 unsafe.Pointer 类型,个别指针没有指针运算。
2.2.5 映射类型
对于一个组合对类型 K、V,类型 map[K]V 是将类型 K 键映射到类型 V 值的哈希表的类型。
2.2.6 通道类型
chan T 是一个通道,容许在并发的 Go 过程之间发送 T 类型的值。
2.2.7 显式类型
除了对接口的反对外,Go 的类型零碎是显示的:类型关键字能够用来定义一个新的命名类型,它与其余具备雷同布局的命名类型(对于构造体来说,雷同的成员按雷同的顺序排列)不同。类型之间的一些转换(如各种整数类型之间的转换)是事后定义好的,增加一个新的类型能够定义额定的转换,但命名类型之间的转换必须始终显式调用。例如,类型关键字能够用来定义 IPv4 地址的类型,基于 32 位无符号整数:
type ipv4addr uint32
通过这个类型定义,ipv4addr(x)将 uint32 值 x 解释为 IP 地址。如果简略地将 x 调配给类型为 ipv4addr 的变量将会是一个类型谬误。
常量表达式既能够是类型化的,也能够是 “ 非类型化的 ”;如果它们所代表的值通过了编译时的查看,那么当它们被调配给一个类型化的变量时,就会被赋予一个类型。
2.2.8 函数类型
函数类型由 func 关键字示意;它们取 0 个或更多的参数并返回 0 个或更多的值,这些值都是要申明类型的。
参数和返回值决定了一个函数的类型;比方,func(string, int32)(int, error)就是输出一个字符串和一个 32 位有符号的整数,并返回一个有符号的整数和一个谬误(内置接口类型)的值的函数类型。
2.2.9 类型上的办法扩大
任何命名的类型都有一个与之相关联的办法汇合。下面的 IP 地址例子能够用一个查看其值是否为已知规范的办法来扩大:
// ZeroBroadcast 报告 addr 是否为 255.255.255.255.255。func (addr ipv4addr) ZeroBroadcast() bool {return addr == 0xFFFFFFFF}
以上的函数在 ipv4addr 上减少了一个办法,但这个办法在 uint32 上没有。
2.2.10 接口零碎
Go 提供了两个性能来取代类继承。
首先是嵌入办法,能够看成是一种自动化的形成模式或委托代理。
第二种是接口,它提供了运行时的多态性。
接口是一类型,它在 Go 的类型零碎中提供了一种无限的构造类型化模式。
一个接口类型的对象同时也有另一种类型的定义对应,这点就像 C ++ 对象同时具备基类和派生类的特色一样。
Go 接口是在 Smalltalk 编程语言的协定根底上设计的。
在形容 Go 接口时应用了鸭式填充这个术语。
尽管鸭式填充这个术语没有准确的定义,它通常是说这些对象的类型一致性没有被动态查看。
因为 Go 接口的一致性是由 Go 编译器动态地查看的,所以 Go 的作者们更喜爱应用构造类型化这个词。
接口类型的定义按名称和类型列出了所需的办法。任何存在与接口类型 I 的所需办法匹配的函数的 T 类型的对象也是类型 I 的对象。类型 T 的定义不须要也不能辨认类型 I。例如,如果 Shape、Square 和 Circle 被定义为:
import "math"
type Shape interface {Area() float64
}
type Square struct { // 注:没有 "实现" 申明
side float64
}
func (sq Square) Area() float64 { return sq.side * sq.side}
type Circle struct { // 这里也没有 "实现" 申明
radius float64
}
func (c Circle) Area() float64 { return math.Pi * math.Pow(c.radius, 2) }
一个正方形和一个圆都隐含着一个形态 (Shape) 类型,并且能够被调配给一个形态 (Shape) 类型的变量。
Go 的接口零碎应用了了构造类型。接口也能够嵌入其余接口,其成果是创立一个组合接口,而这个组合接口正是由实现嵌入接口的类型和新定义的接口所减少的办法来满足的。
Go 规范库在多个中央应用接口来提供通用性,这包含基于 Reader 和 Writer 概念的输入输出零碎。
除了通过接口调用办法,Go 还容许通过运行时类型查看将接口值转换为其余类型。这就是类型断言和类型切换。
空接口 {} 是一个重要的根本状况,因为它能够援用任何类型的选项。它相似于 Java 或 C# 中的 Object 类,能够满足任何类型,包含像 int 这样的内置类型。
应用空接口的代码不能简略地在被援用的对象上调用办法或内置操作符,但它能够存储 interface{}值,通过类型断言或类型切换尝试将其转换为更有用的类型,或者用 Go 的 reflect 包来查看它。
因为 interface{} 能够援用任何值,所以它是一种解脱动态类型化限度的无效形式,就像 C 语言中的 void*,但在运行时会有额定的类型查看。
接口值是应用指向数据的指针和第二个指向运行时类型信息的指针来实现的。与 Go 中其余一些应用指针实现的类型一样,如果未初始化,接口值是零。
2.3 程序包零碎
在 Go 的包零碎中,每个包都有一个门路(如 ”compress/bzip2 “ 或 ”http://golang.org/x/net/html”)和一个名称(如 bzip2 或 html)。
对其余包的定义的援用必须始终以其余包的名称作为前缀,并且只有其余包的大写的名称能力被拜访:io.Reader 是公开的,但 bzip2.reader 不是。
go get 命令能够检索存储在近程资源库中的包,激励开发者在开发包时,在与源资源库绝对应的根底门路
(如 http://example.com/user_name/…)内开发程序包,从而缩小未来在规范库或其余内部库中名称碰撞的可能性。
有人提议 Go 引入一个适合的包治理解决方案,相似于 CPANfor Perl 或 Rust 的 Cargo 零碎或 Node 的 npm 零碎。
2.4 并发:goroutines 和通道
2.4.1【CSP 并发模式】
在计算机科学中,通信程序过程(communicating sequential processes,CSP)是一种形容并发零碎中交互模式的正式语言,它是并发数学实践家族中的一个成员,被称为过程算法(process algebras),或者说过程计算(process calculate),是基于音讯的通道传递的数学实践。
CSP 在设计 Oceam 编程语言时起了很大的影响,同时也影响了 Limbo、RaftLib、Go、Crystal 和 Clojure 的 core.async 等编程语言的设计。
CSP 最早是由 TonyHoare 在 1978 年的一篇论文中形容的,起初有了很大的倒退。
CSP 作为一种工具被理论利用于工业上,用于指定和验证各种不同零碎的并发性能,如 T9000Transputer 以及平安的电子商务系统。
CSP 自身的实践目前也依然是被踊跃钻研的对象,包含减少其理论适用范围的工作,如减少可剖析的零碎规模。
Go 语言有内置的机制和库反对来编写并发程序。并发不仅指的是 CPU 的并行性,还指的是异步性解决:让绝对慢的操作,如数据库或网络读取等操作在做其余工作的同时运行,这在基于事件的服务器中很常见。
次要的并发结构是 goroutine,这是一种轻量级解决类型。一个以 go 关键字为前缀的函数调用会在一个新的 goroutine 中启动这个函数。
语言标准并没有指定如何实现 goroutine,但目前的实现将 Go 过程的 goroutine 复用到一个较小的操作系统线程集上,相似于 Erlang 中的调度。
尽管一个规范的库包具备大多数经典的并发控制结构(mutex 锁等),但 Go 并发程序更偏重于通道,它提供了 goroutines 之间的音讯传性能。
可选的缓冲区以 FIFO 顺序存储音讯,容许发送的 goroutines 在收到音讯之前持续进行。
通道是类型化的,所以 chan T 类型的通道只能用于传输 T 类型的音讯。
非凡语法约定用于对它们进行操作;<-ch 是一个表达式,它使执行中的 goroutine 在通道 ch 上阻塞,直到有一个值进来,而 ch<- x 则是发送值 x(可能阻塞直到另一个 goroutine 接管到这个值)。
内置的相似于开关的抉择语句能够用来实现多通道上的非阻塞通信。Go 有一个内存模型,形容了 goroutine 必须如何应用通道或其余操作来平安地共享数据。
通道的存在使 Go 有别于像 Erlang 这样的 actor 模型式的并发语言,在这种语言中,音讯是间接面向 actor(对应于 goroutine)的。在 Go 中,能够通过在 goroutine 和通道之间放弃一对一的对应关系来,Go 语言也容许多个 goroutine 共享一个通道,或者一个 goroutine 在多个通道上发送和接管音讯。
通过这些性能,人们能够构建像 workerpools、流水线(比如说,在下载文件时,对文件进行解压缩和解析)、带超时的后盾调用、对一组服务的 ” 扇出 ” 并行调用等并发结构。
通道也有一些超过过程间通信的惯例概念的用处,比方作为一个并发平安的回收缓冲区列表,实现 coroutines 和实现迭代器。
Go 的并发相干的构造约定(通道和代替通道输出)来自于 TonyHoare 的通信顺序进程模型。
不像以前的并发编程语言,如 Occam 或 Limbo(Go 的独特设计者 RobPike 曾在此基础上工作过的语言),Go 没有提供任何内置的平安或可验证的并发概念。
尽管在 Go 中,上述的通信解决模型是举荐应用的,但不是惟一的:一个程序中的所有 goroutines 共享一个繁多的地址空间。这意味着可渐变对象和指针能够在 goroutines 之间共享。
2.5 并行编程的舒适度
有一项钻研比拟了一个不相熟 Go 语言的幼稚程序员编写的程序的大小(以代码行数为单位)和速度,以及一个 Go 专家(来自 Google 开发团队)对这些程序的修改,对 Chapel、Cilk 和 IntelTBB 做了同样的钻研。
钻研发现,非专家偏向于用每个递归中的一条 Go 语句来写合成 - 解决算法,而专家则用每个处理器的一条 Go 语句来写分布式工作同步程序。Go 专家的程序通常更快,但也更长。
2.6 条件比赛平安问题
Goroutine 对于如何访问共享数据没有限度,这使得条件比赛成为可能的问题。
具体来说,除非程序通过通道或其余形式显式同步,否则多个 goroutine 共享读写一个内存区域可能会产生问题。
此外,Go 的外部数据结构,如接口值、动静数组头、哈希表和字符串头等外部数据结构也不能幸免于条件比赛,因而在多线程程序中,如果批改这些类型的共享实例没有同步,就会存在影响类型和内存平安的状况。
2.7 二进制生成
gc 工具链中的链接器默认会创立动态链接的二进制文件,因而所有的 Go 二进制文件都包含 Go 运行所须要的内容。
2.8 舍弃的语言特色
Go 成心省略了其余语言中常见的一些性能,包含继承、通用编程、断言、指针运算、隐式类型转换、无标记的联结和标记联结。
2.9 Go 格调特点
Go 作者在 Go 程序的格调方面付出了大量的致力:
- gofmt 工具主动标准了代码的缩进、间距和其余外表级的细节。
- 与 Go 一起散发的工具和库举荐了一些规范的办法,比方 API 文档(godoc)、测试(go test)、构建(go build)、包治理(go get)等等。
- Go 的一些规定跟其余语言不同,例如禁止循环依赖、未应用的变量或导入、隐式类型转换等。
- 某些个性的省略(例如,函数编程的一些捷径,如 map 和 Java 格调的 try/finally 块)编程格调显式化,具体化,简单化。
- Go 团队从第一天开始就公布了一个 Go 的语法应用汇合,起初还收集了一些代码的评论,讲座和官网博客文章,来推广 Go 的格调和编码理念。
三、【Go 的工具】
次要的 Go 发行版包含构建、测试和剖析代码的工具。
go build,它只应用源文件中的信息来构建 Go 二进制文件,不应用独自的 makefiles。
gotest,用于单元测试和微基准
go fmt,用于格式化代码
go get,用于检索和装置近程包。
go vet,动态分析器,查找代码中的潜在谬误。
go run,构建和执行代码的快捷方式
godoc,用于显示文档或通过 HTTP
gorename,用于以类型平安的形式重命名变量、函数等。
go generate,一个规范的调用代码生成器的办法。
它还包含剖析和调试反对、运行时诊断(例如,跟踪垃圾收集暂停)和条件比赛测试器。
第三方工具的生态系统加强了规范的公布零碎,如:
gocode,它能够在许多文本编辑器中主动实现代码,
goimports(由 Go 团队成员提供),它能够依据须要主动增加 / 删除包导入,以及 errcheck,它能够检测可能无心中被疏忽的错误代码。
四、【编辑环境】
风行的 Go 代码工具:
GoLand:JetBrains 公司的 IDE。
VisualStudio Code
LiteIDE:一个 ” 简略、开源、跨平台的 GoIDE”
Vim:用户能够装置插件:
vim-go
五、【利用案例】
用 Go 编写的一些驰名的开源利用包含:
Caddy,一个开源的 HTTP/2web 服务器,具备主动 HTTPS 性能。
CockroachDB,一个开源的、可生存的、强一致性、可扩大的 SQL 数据库。
Docker, 一套用于部署 Linux 容器的工具。
Ethereum,以太币虚拟机区块链的 Go-Ethereum 实现。
Hugo,一个动态网站生成器
InfluxDB,一个专门用于解决高可用性和高性能要求的工夫序列数据的开源数据库。
InterPlanetaryFile System,一个可内容寻址、点对点的超媒体协定。
Juju,由 UbuntuLinux 的包装商 Canonical 公司推出的服务协调工具。
Kubernetes 容器管理系统
lnd,比特币闪电网络的实现。
Mattermost,一个团队聊天零碎
NATSMessaging,是一个开源的消息传递零碎,其外围设计准则是性能、可扩展性和易用性。
OpenShift,云计算服务平台
Snappy, 一个由 Canonical 开发的 UbuntuTouch 软件包管理器。
Syncthing,一个开源的文件同步客户端 / 服务器应用程序。
Terraform,是 HashiCorp 公司的一款开源的多云基础设施配置工具。
其余应用 Go 的出名公司和网站包含:
Cacoo,应用 Go 和 gRPC 渲染用户仪表板页面和微服务。
Chango,程序化广告公司,在其实时竞价零碎中应用 Go。
CloudFoundry,平台即服务零碎
Cloudflare,三角编码代理 Railgun,分布式 DNS 服务,以及密码学、日志、流解决和拜访 SPDY 网站的工具。
容器 Linux(原 CoreOS),是一个基于 Linux 的操作系统,应用 Docker 容器和 rkt 容器。
Couchbase、Couchbase 服务器内的查问和索引服务。
Dropbox,将局部要害组件从 Python 迁徙到了 Go。
谷歌,许多我的项目,特地是下载服务器 http://dl.google.com。
Heroku,Doozer,一个提供锁具服务的公司
HyperledgerFabric,一个开源的企业级分布式分类账我的项目。
MongoDB,治理 MongoDB 实例的工具。
Netflix 的服务器架构的两个局部。
Nutanix,用于其企业云操作系统中的各种微服务。
Plug.dj,一个互动式在线社交音乐流媒体网站。
SendGrid 是一家位于科罗拉多州博尔德市的事务性电子邮件发送和治理服务。
SoundCloud,” 几十个零碎 ”
Splice,其在线音乐合作平台的整个后端(API 和解析器)。
ThoughtWorks,继续传递和即时信息的工具和利用(CoyIM)。
Twitch,他们基于 IRC 的聊天零碎(从 Python 移植过去的)。
Uber,解决大量基于地理信息的查问。
六、【代码示例】
6.1 Hello World
package main
import "fmt"
func main() {fmt.Println("Hello, world!")
}
6.2 并发
package main
import (
"fmt"
"time"
)
func readword(ch chan string) {fmt.Println("Type a word, then hit Enter.")
var word string
fmt.Scanf("%s", &word)
ch <- word
}
func timeout(t chan bool) {time.Sleep(5 * time.Second)
t <- false
}
func main() {t := make(chan bool)
go timeout(t)
ch := make(chan string)
go readword(ch)
select {
case word := <-ch:
fmt.Println("Received", word)
case <-t:
fmt.Println("Timeout.")
}
}
6.3 代码测试
没有测试的代码是不残缺的,因而咱们须要看看代码测试局部的编写。
代码:
func ExtractUsername(email string) string {at := strings.Index(email, "@")
return email[:at]
}
测试案例:
func TestExtractUsername(t *testing.T) {
type args struct {email string}
tests := []struct {
name string
args args
want string
}{{"withoutDot", args{email: "r@google.com"}, "r"},
{"withDot", args{email: "jonh.smith@example.com"}, "jonh.smith"},
}
for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {if got := ExtractUsername(tt.args.email); got != tt.want {t.Errorf("ExtractUsername() = %v, want %v", got, tt.want)
}
})
}
}
6.4 创立后端服务
接下来我写一个例子创立 REST API 后端服务:
咱们的服务提供如下的 API:
###
GET http://localhost:10000/
###
GET http://localhost:10000/all
###
GET http://localhost:10000/article/1
###
POST http://localhost:10000/article HTTP/1.1
{
"Id": "3",
"Title": "Hello 2",
"desc": "Article Description",
"content": "Article Content"
}
###
PUT http://localhost:10000/article HTTP/1.1
{
"Id": "2",
"Title": "Hello 2 Update",
"desc": "Article Description Update",
"content": "Article Content Update"
}
残缺代码:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"github.com/gorilla/mux"
)
type Article struct {
Id string `json:"Id"`
Title string `json:"Title"`
Desc string `json:"desc"`
Content string `json:"content"`
}
var MapArticles map[string]Article
var Articles []Article
func returnAllArticles(w http.ResponseWriter, r *http.Request) {fmt.Println("Endpoint Hit: returnAllArticles")
json.NewEncoder(w).Encode(Articles)
}
func homePage(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Welcome to the HomePage!")
fmt.Println("Endpoint Hit: homePage")
}
func createNewArticle(w http.ResponseWriter, r *http.Request) {reqBody, _ := ioutil.ReadAll(r.Body)
var article Article
json.Unmarshal(reqBody, &article)
Articles = append(Articles, article)
MapArticles[article.Id] = article
json.NewEncoder(w).Encode(article)
}
func updateArticle(w http.ResponseWriter, r *http.Request) {reqBody, _ := ioutil.ReadAll(r.Body)
var article Article
json.Unmarshal(reqBody, &article)
found := false
for index, v := range Articles {
if v.Id == article.Id {
// Found!
found = true
Articles[index] = article
}
}
if !found {Articles = append(Articles, article)
}
MapArticles[article.Id] = article
json.NewEncoder(w).Encode(article)
}
func returnSingleArticle(w http.ResponseWriter, r *http.Request) {vars := mux.Vars(r)
key := vars["id"]
fmt.Fprintf(w, "Key: %s n", key)
json.NewEncoder(w).Encode(MapArticles[key])
}
func handleRequests() {myRouter := mux.NewRouter().StrictSlash(true)
myRouter.HandleFunc("/", homePage)
myRouter.HandleFunc("/all", returnAllArticles)
myRouter.HandleFunc("/article", createNewArticle).Methods("POST")
myRouter.HandleFunc("/article", updateArticle).Methods("PUT")
myRouter.HandleFunc("/article/{id}", returnSingleArticle)
log.Fatal(http.ListenAndServe(":10000", myRouter))
}
func main() {fmt.Println("Rest API is ready ...")
MapArticles = make(map[string]Article)
Articles = []Article{Article{Id: "1", Title: "Hello", Desc: "Article Description", Content: "Article Content"},
Article{Id: "2", Title: "Hello 2", Desc: "Article Description", Content: "Article Content"},
}
for _, a := range Articles {MapArticles[a.Id] = a
}
handleRequests()}
调用增加,更新 API 当前返回所有数据的测试后果:
七、【褒贬不一】
7.1 投诉
MicheleSimionato 对 Go 大加投诉:
接口零碎简洁,并刻意省略了继承。
EngineYard 的 DaveAstels 写道:
Go 是非常容易上手的。很少的根本语言概念,语法也很洁净,设计得很清晰。Go 目前还是实验性的,还有些中央比拟毛糙。
2009 年,Go 被 TIOBE 编程社区指数评比为年度最佳编程语言。
到 2010 年 1 月,Go 的排名达到了第 13 位,超过了 Pascal 等成熟的语言。
但到了 2015 年 6 月,它的排名跌至第 50 位以下,低于 COBOL 和 Fortran。
但截至 2017 年 1 月,它的排名又飙升至第 13 位,显示出它的普及率和采用率有了显著的增长。
Go 被评为 2016 年 TIOBE 年度最佳编程语言。
BruceEckel 曾示意:
C++ 的复杂性(在新的 C ++ 中甚至减少了更多的复杂性),以及由此带来的对生产力的影响,曾经没有任何理由持续应用 C ++ 了。C++ 程序员为了克服 C 语言的一些问题而做出的加强初衷目前曾经没有了意义,而 Go 此时显得更有意义。
2011 年一位 Google 工程师 R.Hundt 对 Go 语言及其 GC 实现与 C ++(GCC)、Java 和 Scala 的比照评估发现。
Go 提供了乏味的语言个性,这也使得 Go 语言有了简洁、标准化的特色。这种语言的编译器还不成熟,这在性能和二进制大小上都有体现。
这一评估收到了 Go 开发团队的快速反应。
IanLance Taylor 因为 Hundt 的评论改良了 Go 代码;
RussCox 随后对 Go 代码以及 C ++ 代码进行了优化,并让 Go 代码的运行速度比 C ++ 略快,比评论中应用的代码性能快了一个数量级以上。
7.2 命名争议
2009 年 11 月 10 日,也就是 Go!编程语言全面公布的当天,Go!编程语言的开发者 FrancisMcCabe(留神是感叹号)要求更改 Google 的语言名称,以防止与他花了 10 年工夫开发的语言混同。
McCabe 示意了对谷歌这个 ’ 大块头 ’ 最终会碾压他 ” 的担心,这种担心引起了 120 多名开发者的共鸣,他们在 Google 官网的问题线程上评论说他们应该改名,有些人甚至说这个问题违反了 Google 的座右铭:” 不要作恶。”
2010 年 10 月 12 日,谷歌开发者 RussCox 敞开了这个问题,自定义状态为 ” 可怜 ”,并附上了以下评论:
“ 有很多计算产品和服务都被命名为 Go。在咱们公布以来的 11 个月里,这两种语言的混同度极低。”
7.3【批评】
Go 的批评家们的观点:
- 通用程序设计不足参数多态性,导致代码反复或不平安的类型转换以及扰乱流程的随意性。
- Go 的 nil,加上代数类型的缺失,导致故障解决和根本问题的防止很艰难。
- Go 不容许在以后行中呈现开局括号,这就迫使所有的 Go 程序员必须应用雷同的括号款式。
八、【小结】
本文从 Go 的语法,类型零碎,编码格调,语言工具,编码工具和应用案例等几方面对 Go 语言进行了学习和探讨,心愿能够抛砖引玉,对 Go 语言感兴趣的同仁有所裨益。
点击关注,第一工夫理解华为云陈腐技术~