Go言语分辨于其他言语的特点
序言 :
跟着编程言语的言语于其言语展开,Go 还很年青 。分辨它于 2009 年 11 月 10 日初度宣布。特点其成立者Robert Griesemer Rob Pike 和 Ken Thompson在 Google 工作,言语于其言语在那儿何处除夜局限扩大年夜大年夜大年夜大年夜的分辨挑衅鼓舞他们将 Go 筹划为一种疾速有效的编程措置筹划 ,用于具有除夜型代码库 、特点治出处多个斥地人员 ,言语于其言语具有严格的分辨功用请求 ,并超出多个群集和措置中心 。特点 Go 的言语于其言语草创人在成立他们的新言语时也借此机会进修了其他编程言语的益处、偏向偏向和裂缝 。分辨下场是特点一种干净、了然和合用的言语于其言语言语 ,具有绝对较少的分辨呼唤和下场集。
1. Go 老是特点在构建中包含二进制文件
Go 运转时供给内存分拨 、残剩群集 、并发支撑和群集等处事 。它被编译到每个 Go 二进制文件中 。这与良多其他言语不合,个中良多言语独霸需求与法度圭表类型一同拆卸才调正常工作的虚构机。
将运转时直接包含在二进制文件中使得分发和运转 Go 法度圭表类型变得特别很是随便 ,并阻拦了运转时和法度圭表类型之间的不兼容问题。Python 、Ruby 和 JavaScript 等言语的虚构机也没有针对残剩群集和内存分拨举办优化,这诠释了 Go 绝对其他近似言语的优胜速度。比如 ,Go 将尽大年夜大年夜约多的存储在仓库中,个中数据按按序列举以便比堆更快地访谒。稍后会具体引见。
关于 Go 的静态二进制文件的末尾一件事是,因为不须要运转内部依托项 ,所以它们启动得特别很是快 。假定您独霸Google App Engine 之类的处事 ,这是一种在 Google Cloud 上运转的平台即处事 ,它可以将您的独霸法度圭表类型缩减到零实例以俭仆云成本,这将特别很是有效 。当收到新请求时,App Engine 可以在眨眼间启动 Go 法度圭表类型的一个实例。在 Python 或 Node 中的不异体验但凡会招致 3-5 秒(或更长时分)的等待,因为所需的虚构气候也会与新实例一同启动 。
2. Go 没有针对法度圭表类型依托的集结托管处事
为了访谒已宣布的 Go 法度圭表类型,斥地人员不依托集结托管的处事,比如Java 的Maven Central或JavaScript的NPM注册表。相反,项目经由过程其源代码存储库(最罕有的是 Github)共享。在go install呼唤行准予以这类编制下载库。 为甚么我快活喜悦爱好这个下场 ?我不时认为像 Maven Central 、PIP 和 NPM 多么的集结托管的依托处事有点令人生畏的黑盒子,或承诺以笼统出下载和拆卸依托项的贫穷,但不成阻拦地会在依托项偏向时激起恐怖的心跳停止产生发火。
此外 ,将的的模块供给给其别人就像将其放进版本独霸系同一样复杂,这是分发法度圭表类型的一种特别很是复杂的编制。
3. Go 是按值调用的
在 Go 中,当你供给一个原始值(数字、布尔值或字符串)或一个筹划体(类对象的大年夜大年夜致等价物)作为函数的参数时 ,Go 老是会复制变量的值 。
在 Java 、Python 和 JavaScript 等良多其他言语中,原语是按值传递的,但对象(类实例)是按援引传递的 ,这意味着领受函数理论上领受的是指向原始对象的指针 ,而不是其副本。在领受函数中对对象所做的任何变换都邑回响在原始对象中。
在 Go 中 ,筹划体和原语默许按值传递,可以选择传递指针 ,经由过程独霸星号运算符:
// 按值传递func MakeNewFoo(f Foo ) (Foo, error) { f.Field1 = "New val" f.Field2 = f.Field2 + 1 return f, nil }上述函数领受 Foo 的副本并前去一个新的 Foo 对象。
// 经由过程援引传递func MutateFoo(f *Foo ) error { f.Field1 = "New val" f.Field2 = 2 return nil }上面的函数领受一个指向 Foo 的指针并改削原始对象。
按值调用与按援引调用的这类较着分辨使您的意图不问可知 ,并降低了调用函数有时中改削传进对象的大年夜大年夜约性(当它不睬应产生发火时(良多初学者斥地人员很难做到这一点)握紧)。
正如麻省理工总结的 :“可变性使得邃晓你的法度圭表类型在做甚么变得愈加艰苦 ,并且更难以奉行契约”
此外,按值调用光鲜较着促进了残剩群集器的工作,这意味着独霸法度圭表类型更快、内存屈就更高。这篇文章得出的结论是,指针追踪(从堆中检索指针值)比从延续仓库中检索值慢 10 到 20 倍。要记住的一个很好的经验律例是:从内存中读取的最快编制是按序读取,这意味着将随机存储在 RAM 中的指针数量促进到起码。
4. 'defer' 关头字
在NodeJS 中,在我最早独霸knex.js之前 ,我会经由过程成立一个数据库池来手动治理我的代码中的数据库邻接,然后在每个函数中从池中翻开一个新邻接 ,一旦所需的数据库 CRUD 下场已完成 。
这有点像呵护恶梦,因为假定我没有在每个函数停止时释放邻接,未释放的数据库邻接的数量会慢慢添加 ,直到池中没有更多可用邻接 ,然后中缀独霸法度圭表类型。
理论气候是 ,法度圭表类型经常需求释放、拾掇和裁撤成本、文件、邻接等 ,是以 Go 引进了defer关头字作为治理这些的有效编制。
任何故defer开首的语句都邑迟误对它的调用 ,直到邻近的函数介入。这意味着您可以将拾掇/拆卸代码放在函数的顶部(很较着),晓得一旦函数完成它就会如斯。
func main() { if len(os.Args) < 2 { log.Fatal("no file specified") } f, err := os.Open(os.Args[1]) if err != nil { log.Fatal(err) } defer f.Close() data := make([]byte, 2048) for { count, err := f.Read(data) os.Stdout.Write(data[:count]) if err != nil { if err != io.EOF { log.Fatal(err) } break } } }不才面的例子中 ,文件封锁编制被推迟了。我快活喜悦爱好这类在函数顶部声明你的外务措置意图的编制 ,然后遗忘它 ,晓得一旦函数介入它就会完成它的工作。
5. Go 采取了函数式编程的最好特点
函数式编程是一种高效且富有创作创作创造性的范式,侥幸的是 Go 采取了函数式编程的最好特点。在Go中 :
- 函数是值 ,这意味着它们可以作为值添加到映照中 ,作为参数传递给其他函数,设置为变量 ,并从函数前去(称为“高阶函数”,在 Go 中经常独霸装潢器成立中心件图案)。
- 可以成立和主动调用匿名函数 。
- 在其他函数内声明的函数准予闭包(在函数内声明的函数可以访谒和改削在内部函数中声明的变量) 。在惯用的 Go 中 ,闭包被普及独霸来限制函数的局限 ,并设置函数然后在其逻辑中独霸的外形 。
func StartTimer (name string) func(){ t := time.Now() log.Println(name, "started") return func() { d := time.Now().Sub(t) log.Println(name, "took", d) }}func RunTimer() { stop := StartTimer("My timer") defer stop() time.Sleep(1 * time.Second)}上面是一个闭包的例子。'StartTimer' 函数前去一个新函数,它经由过程闭包可以访谒在其出世局限内设置的 't' 值 。然后,此函数可以将往后时分与“t”的值举办斗劲 ,从而成立一个有效的计时器。感激冲动冲动冲动Mat Ryer的这个例子。
6. Go 有隐式接口
任何不雅不雅不雅不雅鉴赏过有关SOLID编码和筹划编制的文献的人都大年夜大年夜约传闻过“优先组合胜过延续”的行动禅 。简而言之,这注解您理应将营业逻辑分化为不合的接口,而不是依托于来自父类的属性和逻辑的分层延续。
此外一个风行的编制是“为接口编程,而不是完成”: API 理应只宣布其预期行动的契约(其编制签名) ,而不是有关若何完成该行动的具体信息 。
这二者都注解接口在现代编程中的次要性。
是以,Go 支撑接口也就层见迭出了。理论上 ,接口是 Go 中独一的笼统圭表类型 。
可是,与其他言语不合,Go 中的接口不是显式完成的,而是隐式完成的。具体圭表类型不声明它完成了接口。相反,假定为该具体圭表类型设置的编制集包含底层接口的全数编制集 ,则Go 认为该对象完成了 inte***ce。
这类隐式接口完成(正式称为筹划圭表类型)准予 Go 强逼奉行圭表类型安然和解耦,贯穿连接静态言语中默示出的除夜部分矫捷性。
比照之下,显式接口将客户端和完成绑定在一同 ,比如 ,在 Java 中更调依托项比在 Go 中艰苦良多 。
// 这是一个接口声明(称为Logic)type Logic inte***ce { Process (data string) string }type LogicProvider struct { }// 这是 LogicProvider 上名为“Process”的编制 struct func (lp LogicProvider) Process (data string) string { // 营业逻辑}// 这是具有 Logic 接口作为属性的客户端筹划type Client struct { L Logic }func(c Client) Program() { // 从某处掉落踪掉落踪数据 cLProcess(data) }func main() { c := Client { L: LogicProvider{ }, } c.Program() }LogicProvider 中没有任何声分明现它契合Logic接口。这意味着客户端将来可以轻松更调其逻辑供给法度圭表类型 ,只需该逻辑供给法度圭表类型包含底层接口 ( Logic ) 的全数编制集 。
7.偏向措置
Go 中的偏向措置编制与其他言语除夜不不异。简而言之,Go 经由过程前去一个 error 圭表类型的值作为函数的末尾一个前去值来措置偏向。
当函数按预期奉行时 ,偏向参数前去nil,不然前去偏向值 。调用函数然后搜检偏向前去值 ,并措置偏向 ,或抛出本身的偏向 。
// 函数前去一个整数和一个偏向func calculateRemainder(numerator int, denominator int) ( int, error ) { // if denominator == 0 { return 9, errors.New("denominator is 0" } // 没有偏向前去 return numerator / denominator, nil }Go 以这类编制运转是有启事的 :它迫使编码人员思虑特别很是并切确措置它们。传统的 try-catch 特别很是还会在代码中添加起码一个新的代码路途,并以难以屈就的编制缩进代码 。Go 更快活喜悦爱好将“欢愉路途”视为非缩进代码,在“欢愉路途”完成之前辨认并前去任何偏向。
8.并发
可以说是 Go 最有名的特点 ,并发准予措置在机械或处事器上的可用内核数量上并走运转 。当孤单的过程不彼此依托(不须要按序运转)并且时分功用相当次要时,并发性最居心义 。这但凡是 I/O 请求的气候,个中读取或写进磁盘或群集的速度比除最宏壮的内存中过程以外的全数过程慢几个数量级 。 函数调用前的“ go ”关头字将同时运转该函数。
func process(val int) int { // 用 val 做一些工作}// 对 'in' 中的每个值 ,同时运转 process 函数
,// 并将 process 的下场读取到 'out' func runConcurrently(in <-chan int, out chan<- int){ go func() { for val := range in { result := process(val) out <- result } } }Go 中的并发是一项深切且相如今级的下场,但在居心义的中心,它供给了一种有效的编制来确保法度圭表类型的最好功用 。
9. Go 标准库
Go 有一个“包含电池”的理念,现代编程言语的良多请求都被纳进标准库,这使法度圭表类型员的糊口变得愈加复杂。 如前所述,Go 是一种绝对年青的言语,这意味着标准库中可以知足现代独霸法度圭表类型的良多问题/请求 。
一方面 ,Go 为群集(不凡是 HTTP/2)和文件治理供给了全国一流的支撑 。它还供给原生 JSON 编码和解码。是以,设置处事器来措置 HTTP 请求并前去照顾(JSON 或其他)特别很是复杂 ,这诠释了 Go 在基于 REST 的 HTTP Web 处事斥地中的风行 。
正如Mat Ryer还指出的那样,标准库是开源的,是进修 Go 最好幻想的尽佳编制。
到此这篇关于Go 有别于其他言语的九个特点 的文章就引见到这了,更多相干Go 有别于其他言语的特点 内容请搜刮完竣下载之前的文章或延续不雅不雅不雅不雅鉴赏上面的相干文章希看大年夜师往后多多支撑完竣下载!
序言 :
跟着编程言语的言语于其言语展开,Go 还很年青 。分辨它于 2009 年 11 月 10 日初度宣布。特点其成立者Robert Griesemer Rob Pike 和 Ken Thompson在 Google 工作,言语于其言语在那儿何处除夜局限扩大年夜大年夜大年夜大年夜的分辨挑衅鼓舞他们将 Go 筹划为一种疾速有效的编程措置筹划 ,用于具有除夜型代码库 、特点治出处多个斥地人员 ,言语于其言语具有严格的分辨功用请求 ,并超出多个群集和措置中心 。特点 Go 的言语于其言语草创人在成立他们的新言语时也借此机会进修了其他编程言语的益处、偏向偏向和裂缝 。分辨下场是特点一种干净、了然和合用的言语于其言语言语 ,具有绝对较少的分辨呼唤和下场集。
1. Go 老是特点在构建中包含二进制文件
Go 运转时供给内存分拨 、残剩群集 、并发支撑和群集等处事 。它被编译到每个 Go 二进制文件中 。这与良多其他言语不合,个中良多言语独霸需求与法度圭表类型一同拆卸才调正常工作的虚构机。
将运转时直接包含在二进制文件中使得分发和运转 Go 法度圭表类型变得特别很是随便 ,并阻拦了运转时和法度圭表类型之间的不兼容问题。Python 、Ruby 和 JavaScript 等言语的虚构机也没有针对残剩群集和内存分拨举办优化,这诠释了 Go 绝对其他近似言语的优胜速度。比如 ,Go 将尽大年夜大年夜约多的存储在仓库中,个中数据按按序列举以便比堆更快地访谒。稍后会具体引见。
关于 Go 的静态二进制文件的末尾一件事是,因为不须要运转内部依托项 ,所以它们启动得特别很是快 。假定您独霸Google App Engine 之类的处事 ,这是一种在 Google Cloud 上运转的平台即处事 ,它可以将您的独霸法度圭表类型缩减到零实例以俭仆云成本,这将特别很是有效 。当收到新请求时,App Engine 可以在眨眼间启动 Go 法度圭表类型的一个实例。在 Python 或 Node 中的不异体验但凡会招致 3-5 秒(或更长时分)的等待,因为所需的虚构气候也会与新实例一同启动 。
2. Go 没有针对法度圭表类型依托的集结托管处事
为了访谒已宣布的 Go 法度圭表类型,斥地人员不依托集结托管的处事,比如Java 的Maven Central或JavaScript的NPM注册表。相反,项目经由过程其源代码存储库(最罕有的是 Github)共享。在go install呼唤行准予以这类编制下载库。 为甚么我快活喜悦爱好这个下场 ?我不时认为像 Maven Central 、PIP 和 NPM 多么的集结托管的依托处事有点令人生畏的黑盒子,或承诺以笼统出下载和拆卸依托项的贫穷,但不成阻拦地会在依托项偏向时激起恐怖的心跳停止产生发火。
此外 ,将的的模块供给给其别人就像将其放进版本独霸系同一样复杂,这是分发法度圭表类型的一种特别很是复杂的编制。
3. Go 是按值调用的
在 Go 中,当你供给一个原始值(数字、布尔值或字符串)或一个筹划体(类对象的大年夜大年夜致等价物)作为函数的参数时 ,Go 老是会复制变量的值 。
在 Java 、Python 和 JavaScript 等良多其他言语中,原语是按值传递的,但对象(类实例)是按援引传递的 ,这意味着领受函数理论上领受的是指向原始对象的指针 ,而不是其副本。在领受函数中对对象所做的任何变换都邑回响在原始对象中。
在 Go 中 ,筹划体和原语默许按值传递,可以选择传递指针 ,经由过程独霸星号运算符:
// 按值传递func MakeNewFoo(f Foo ) (Foo, error) { f.Field1 = "New val" f.Field2 = f.Field2 + 1 return f, nil }上述函数领受 Foo 的副本并前去一个新的 Foo 对象。
// 经由过程援引传递func MutateFoo(f *Foo ) error { f.Field1 = "New val" f.Field2 = 2 return nil }上面的函数领受一个指向 Foo 的指针并改削原始对象。
按值调用与按援引调用的这类较着分辨使您的意图不问可知 ,并降低了调用函数有时中改削传进对象的大年夜大年夜约性(当它不睬应产生发火时(良多初学者斥地人员很难做到这一点)握紧)。
正如麻省理工总结的 :“可变性使得邃晓你的法度圭表类型在做甚么变得愈加艰苦 ,并且更难以奉行契约”
此外,按值调用光鲜较着促进了残剩群集器的工作,这意味着独霸法度圭表类型更快、内存屈就更高。这篇文章得出的结论是,指针追踪(从堆中检索指针值)比从延续仓库中检索值慢 10 到 20 倍。要记住的一个很好的经验律例是:从内存中读取的最快编制是按序读取,这意味着将随机存储在 RAM 中的指针数量促进到起码。
4. 'defer' 关头字
在NodeJS 中,在我最早独霸knex.js之前 ,我会经由过程成立一个数据库池来手动治理我的代码中的数据库邻接,然后在每个函数中从池中翻开一个新邻接 ,一旦所需的数据库 CRUD 下场已完成 。
这有点像呵护恶梦,因为假定我没有在每个函数停止时释放邻接,未释放的数据库邻接的数量会慢慢添加 ,直到池中没有更多可用邻接 ,然后中缀独霸法度圭表类型。
理论气候是 ,法度圭表类型经常需求释放、拾掇和裁撤成本、文件、邻接等 ,是以 Go 引进了defer关头字作为治理这些的有效编制。
任何故defer开首的语句都邑迟误对它的调用 ,直到邻近的函数介入。这意味着您可以将拾掇/拆卸代码放在函数的顶部(很较着),晓得一旦函数完成它就会如斯。
func main() { if len(os.Args) < 2 { log.Fatal("no file specified") } f, err := os.Open(os.Args[1]) if err != nil { log.Fatal(err) } defer f.Close() data := make([]byte, 2048) for { count, err := f.Read(data) os.Stdout.Write(data[:count]) if err != nil { if err != io.EOF { log.Fatal(err) } break } } }不才面的例子中 ,文件封锁编制被推迟了。我快活喜悦爱好这类在函数顶部声明你的外务措置意图的编制 ,然后遗忘它 ,晓得一旦函数介入它就会完成它的工作。
5. Go 采取了函数式编程的最好特点
函数式编程是一种高效且富有创作创作创造性的范式,侥幸的是 Go 采取了函数式编程的最好特点。在Go中 :
- 函数是值 ,这意味着它们可以作为值添加到映照中 ,作为参数传递给其他函数,设置为变量 ,并从函数前去(称为“高阶函数”,在 Go 中经常独霸装潢器成立中心件图案)。
- 可以成立和主动调用匿名函数 。
- 在其他函数内声明的函数准予闭包(在函数内声明的函数可以访谒和改削在内部函数中声明的变量) 。在惯用的 Go 中 ,闭包被普及独霸来限制函数的局限 ,并设置函数然后在其逻辑中独霸的外形 。
func StartTimer (name string) func(){ t := time.Now() log.Println(name, "started") return func() { d := time.Now().Sub(t) log.Println(name, "took", d) }}func RunTimer() { stop := StartTimer("My timer") defer stop() time.Sleep(1 * time.Second)}上面是一个闭包的例子。'StartTimer' 函数前去一个新函数,它经由过程闭包可以访谒在其出世局限内设置的 't' 值 。然后,此函数可以将往后时分与“t”的值举办斗劲 ,从而成立一个有效的计时器。感激冲动冲动冲动Mat Ryer的这个例子。
6. Go 有隐式接口
任何不雅不雅不雅不雅鉴赏过有关SOLID编码和筹划编制的文献的人都大年夜大年夜约传闻过“优先组合胜过延续”的行动禅 。简而言之,这注解您理应将营业逻辑分化为不合的接口,而不是依托于来自父类的属性和逻辑的分层延续。
此外一个风行的编制是“为接口编程,而不是完成”: API 理应只宣布其预期行动的契约(其编制签名) ,而不是有关若何完成该行动的具体信息 。
这二者都注解接口在现代编程中的次要性。
是以,Go 支撑接口也就层见迭出了。理论上 ,接口是 Go 中独一的笼统圭表类型 。
可是,与其他言语不合,Go 中的接口不是显式完成的,而是隐式完成的。具体圭表类型不声明它完成了接口。相反,假定为该具体圭表类型设置的编制集包含底层接口的全数编制集 ,则Go 认为该对象完成了 inte***ce。
这类隐式接口完成(正式称为筹划圭表类型)准予 Go 强逼奉行圭表类型安然和解耦,贯穿连接静态言语中默示出的除夜部分矫捷性。
比照之下,显式接口将客户端和完成绑定在一同 ,比如 ,在 Java 中更调依托项比在 Go 中艰苦良多 。
// 这是一个接口声明(称为Logic)type Logic inte***ce { Process (data string) string }type LogicProvider struct { }// 这是 LogicProvider 上名为“Process”的编制 struct func (lp LogicProvider) Process (data string) string { // 营业逻辑}// 这是具有 Logic 接口作为属性的客户端筹划type Client struct { L Logic }func(c Client) Program() { // 从某处掉落踪掉落踪数据 cLProcess(data) }func main() { c := Client { L: LogicProvider{ }, } c.Program() }LogicProvider 中没有任何声分明现它契合Logic接口。这意味着客户端将来可以轻松更调其逻辑供给法度圭表类型 ,只需该逻辑供给法度圭表类型包含底层接口 ( Logic ) 的全数编制集 。
7.偏向措置
Go 中的偏向措置编制与其他言语除夜不不异。简而言之,Go 经由过程前去一个 error 圭表类型的值作为函数的末尾一个前去值来措置偏向。
当函数按预期奉行时 ,偏向参数前去nil,不然前去偏向值 。调用函数然后搜检偏向前去值 ,并措置偏向 ,或抛出本身的偏向 。
// 函数前去一个整数和一个偏向func calculateRemainder(numerator int, denominator int) ( int, error ) { // if denominator == 0 { return 9, errors.New("denominator is 0" } // 没有偏向前去 return numerator / denominator, nil }Go 以这类编制运转是有启事的 :它迫使编码人员思虑特别很是并切确措置它们。传统的 try-catch 特别很是还会在代码中添加起码一个新的代码路途,并以难以屈就的编制缩进代码 。Go 更快活喜悦爱好将“欢愉路途”视为非缩进代码,在“欢愉路途”完成之前辨认并前去任何偏向。
8.并发
可以说是 Go 最有名的特点 ,并发准予措置在机械或处事器上的可用内核数量上并走运转 。当孤单的过程不彼此依托(不须要按序运转)并且时分功用相当次要时,并发性最居心义 。这但凡是 I/O 请求的气候,个中读取或写进磁盘或群集的速度比除最宏壮的内存中过程以外的全数过程慢几个数量级 。 函数调用前的“ go ”关头字将同时运转该函数。
func process(val int) int { // 用 val 做一些工作}// 对 'in' 中的每个值 ,同时运转 process 函数
,// 并将 process 的下场读取到 'out' func runConcurrently(in <-chan int, out chan<- int){ go func() { for val := range in { result := process(val) out <- result } } }Go 中的并发是一项深切且相如今级的下场,但在居心义的中心,它供给了一种有效的编制来确保法度圭表类型的最好功用 。
9. Go 标准库
Go 有一个“包含电池”的理念,现代编程言语的良多请求都被纳进标准库,这使法度圭表类型员的糊口变得愈加复杂。 如前所述,Go 是一种绝对年青的言语,这意味着标准库中可以知足现代独霸法度圭表类型的良多问题/请求 。
一方面 ,Go 为群集(不凡是 HTTP/2)和文件治理供给了全国一流的支撑 。它还供给原生 JSON 编码和解码。是以,设置处事器来措置 HTTP 请求并前去照顾(JSON 或其他)特别很是复杂 ,这诠释了 Go 在基于 REST 的 HTTP Web 处事斥地中的风行 。
正如Mat Ryer还指出的那样,标准库是开源的,是进修 Go 最好幻想的尽佳编制。
到此这篇关于Go 有别于其他言语的九个特点 的文章就引见到这了,更多相干Go 有别于其他言语的特点 内容请搜刮完竣下载之前的文章或延续不雅不雅不雅不雅鉴赏上面的相干文章希看大年夜师往后多多支撑完竣下载!













