关于go:深入分析Go语言与C的异同

2次阅读

共计 7622 个字符,预计需要花费 20 分钟才能阅读完成。

摘要:本文由葡萄城技术团队于思否原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供业余的开发工具、解决方案和服务,赋能开发者。

前言

为了更加深刻地介绍 Go 语言以及与 C#语言的比拟,本文将会从多个维度登程进行具体的论述。首先,将从 Go 语言的关键字方面介绍 Go 与 C# 在语言个性上的异同,并且探讨两种语言在关键字方面的优化和不足之处。其次,本文将通过代码示例、性能测试等形式,展现 Go 语言在关键字方面的劣势,从而为读者呈现出 Go 语言的弱小之处。除此之外,为了更好地帮忙读者了解 Go 语言,本文还将介绍一些优良的 Go 语言工具和社区资源,供读者进一步学习和摸索。置信通过这些内容的全面介绍,读者们会对 Go 语言有更全面深刻的意识和理解。

文章目录:

1.Go 的前世今生

​ 1.1Go 语言诞生的过程

​ 1.2 逐渐成型

​ 1.3 正式公布

​ 1.4 Go 装置领导

2.Go 和 C# 的关键字比拟

​ 2.1Go 与 C# 都有的关键字

​  2.1.1.Var

​  2.1.2. Switch-case-default

​  2.1.3.If-else

​  2.1.4. For

​  2.1.5. Struct

​​ 2.2Go 与 C# 不太一样然而意思差不多的关键字

​  2.2.1. Package 与 namespace

​​  2.2.2. Import 与 using

​​  2.2.3. Type 与 class

​  2.2.4. Defer 与 finally

​ 2.3Go 有而 C# 没有的关键字

​​  2.3.1. Fallthrough

​​  2.3.2.Func

3. 文章小结

4. 扩大链接

1.Go 的前世今生

1.1Go 语言诞生的过程

话说早在 2007 年 9 月的一天,Google 工程师 Rob Pike 和平常一样启动了一个 C++ 我的项目的构建,依照他之前的教训,这个构建应该须要继续 1 个小时左右。这时他就和 Google 公司的另外两个共事 Ken Thompson 以及 Robert Griesemer 开始吐槽并且说出了本人想搞一个新语言的想法。过后 Google 外部次要应用 C++ 构建各种零碎,但 C++ 复杂性微小并且原生短少对并发的反对,使得这三位大佬苦恼不已。

第一天的闲聊初有功效,他们迅速构想了一门新语言:可能给程序员带来高兴,可能匹配将来的硬件发展趋势以及满足 Google 外部的大规模网络服务。并且在第二天,他们又碰头开始认真构思这门新语言。第二天会后,Robert Griesemer 收回了如下的一封邮件:

能够从邮件中看到,他们对这个新语言的冀望是:在 C 语言的根底上,批改一些谬误,删除一些诟病的个性,减少一些缺失的性能。比方修复 Switch 语句,退出 import 语句,减少垃圾回收,反对接口等。而这封邮件,也成了 Go 的第一版设计初稿。

在这之后的几天,Rob Pike 在一次开车回家的路上,为这门新语言想好了名字 Go。在他心中,”Go”这个单词短小,容易输出并且能够很轻易地在其后组合其余字母,比方 Go 的工具链:goc 编译器、goa 汇编器、gol 连接器等,并且这个单词也正好合乎他们对这门语言的设计初衷:简略。

1.2 逐渐成型

在对立了 Go 的设计思路之后,Go 语言就正式开启了语言的设计迭代和实现。2008 年,C 语言之父,大佬肯·汤普森实现了第一版的 Go 编译器,这个版本的 Go 编译器还是应用 C 语言开发的,其次要的工作原理是将 Go 编译成 C,之后再把 C 编译成二进制文件。到 2008 年中,Go 的第一版设计就根本完结了。这时,同样在谷歌工作的伊恩·泰勒(Ian Lance Taylor)为 Go 语言实现了一个 gcc 的前端,这也是 Go 语言的第二个编译器。伊恩·泰勒的这一成绩不仅仅是一种激励,也证实了 Go 这一新语言的可行性。有了语言的第二个实现,对 Go 的语言标准和规范库的建设也是很重要的。随后,伊恩·泰勒以团队的第四位成员的身份正式退出 Go 语言开发团队,前面也成为了 Go 语言设计和实现的核心人物之一。罗斯·考克斯(Russ Cox)是 Go 外围开发团队的第五位成员,也是在 2008 年退出的。进入团队后,罗斯·考克斯利用函数类型是“一等公民”,而且它也能够领有本人的办法这个个性奇妙设计出了 http 包的 HandlerFunc 类型。这样,咱们通过显式转型就能够让一个一般函数成为满足 http.Handler 接口的类型了。不仅如此,罗斯·考克斯还在过后设计的根底上提出了一些更泛化的想法,比方 io.Reader 和 io.Writer 接口,这就奠定了 Go 语言的 I/O 构造模型。起初,罗斯·考克斯成为 Go 核心技术团队的负责人,推动 Go 语言的继续演变。到这里,Go 语言最后的外围团队造成,Go 语言迈上了稳固演变的路线。

1.3 正式公布

2009 年 10 月 30 日,罗伯·派克在 Google Techtalk 上做了一次无关 Go 语言的演讲,这也是 Go 语言第一次公之于众。十天后,也就是 2009 年 11 月 10 日,谷歌官网发表 Go 语言我的项目开源,之后这一天也被 Go 官网确定为 Go 语言的诞生日。

(Go 语言吉祥物 Gopher)

1.4.Go 装置领导

1.Go 语言安装包下载

Go 官网:https://golang.google.cn/

抉择对应的装置版本即可(倡议抉择.msi 文件)。

2. 查看是否装置胜利 + 环境是否配置胜利

关上命令行:win + R 关上运行框,输出 cmd 命令,关上命令行窗口。

命令行输出 go version 查看装置版本,显示下方内容即为装置胜利。

2.Go 和 C# 的关键字比拟

Go 有 25 个关键字,而 C#则有 119 个关键字(其中蕴含 77 个根底关键字和 42 个上下文关键字)。单从数量上来讲,C#的数量是 Go 的 5 倍之多,这也是 Go 比 C# 更简略的起因之一。

Go 中的 25 个关键字:

break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

(Go 关键字)

2.1Go 与 C# 都有的关键字

  • break
  • case
  • const
  • continue
  • default
  • else
  • for
  • goto
  • if
  • interface
  • return
  • struct
  • switch
  • var

以上 14 个关键字是 Go 和 C# 共有的,它们之中大部分的用法都是完全相同的,这里重点说一下在 Go 中有非凡语法的关键字。

2.1.1.Var

Var 在 Go 中用来示意定义变量,但语法和 C#不同。C# 中只有一种定义变量的办法,而 Go 中有两种,它们别离是:

  • 一般形式
var i int = 1

这种形式是 Go 的原始变量定义形式,个别包级别的变量都是这样定义的,并且如果定义那些编译器能够主动推断的类型,比方上述的例子,其后的类型能够省略。

  • 语法糖(是的,Go 中也有语法糖…)
i, j := 1, "hello"

上述代码可简写为语法糖模式。事实上,Go 代码中,90% 变量都以此形式定义,因为简直所有函数都有多个返回值,这种定义形式可省去许多麻烦。

2.1.2.Switch-case-default

Switch-case 是一个连用的办法,然而 case 和 default 这两个关键字在 Go 中除了能够和 switch 连用,还能够和 select 语句连用。

同时 Go 中默认把 switch 语句的一个弊病修复了,即 switch 子句中不必再写 break 了。

switch n := "a"; n {

case n == "a":

fmt.Println("a")

case n == "b":

fmt.Println("b")

case n == "c":

fmt.Println("c")

}

下面这段代码的 fmt 是 Go 中的规范输入包,其中的 Println 函数等同于 C# 中的 Console.WriteLine 办法。同时这段代码的最终后果只会输入 a,而 在 C#中,同样的代码会把 abc 全副输入进去,这也是 Go 为何比 C# 简略的起因之一。

除此之外,switch 语句前面呈现了一种全新的写法:n := “a”; n,这种写法在 Go 中的管制语句(if, else if, switch-case, for)中都能够应用,分号前是变量的定义,分号后是定义的判断条件。这种语法长处相似于 C# 中的一般 for 循环的前两个子句。

最初,能够发现 switch 之后没有跟小括号,因为在 Go 中,管制块的子句前面都是不须要写小括号的,如果写了同样会被 gofmt 主动格式化掉。

2.1.3. If-else

Go 中的 if-else 和 C# 简直也是雷同的,它俩最大的区别是 Go 中非凡语法,能够在 if-else 管制块中间接给变量赋值并且在管制块中应用这些值。

func isEven(n int) bool {return n % 2 == 0}

func main() {if n := rand.Intn(1000); isEven(n) {fmt.Printf("%d 是偶数 \\n", n)

} else {fmt.Printf("%d 是奇数 \\n", n)

}

}

2.1.4. For

Go 中的循环管制语句有且只有一个 for 关键字。而 C# 中的 while、foreach 等在 Go 中都是通过 for 的各种变形达成的。

  • while 语句
for true {// ...}
  • for 语句
for i := 0; i < n; i++ {// ...}

Go 中一般的 for 循环和 C# 中惟一的差异就是 i++ 从表达式变成了语句。也就是说,Go 中没有 i = i++ 这样的语法,也没有 ++ i 这样的语法,只有 i ++ 这种语法。

  • foreach 语句
array := [5]int{1, 2, 3, 4, 5}

for index, value := range array {// ...}

foreach 语句的写法和 C# 中很不雷同,上述的例子是 foreach 遍历一个 int 类型的数组,其中用到了一个 range 关键字,这个关键字会把数组拆分成两个迭代子对象 index 和 value,for range 能够遍历数组、切片、字符串、map 及通道(channel), 这个语法同样相似于 JavaScript 的循环语法。例如上面的代码就是遍历数组中的值并输入:

for key, value := range []int{1, 2, 3, 4} {fmt.Printf("key:%d value:%d\\n", key, value)

}

代码输入如下:

key:0 value:1

key:1 value:2

key:2 value:3

key:3 value:4

2.1.5 Struct

Go 中的 struct 关键字和 C#中的作用是雷同的,即定义一个构造体。因为 Go 中是没有类这个概念的,所以 struct 就相当于是 C# 中 class 的定义。同样的,struct 在 Go 中是 值类型 构造,因而应用的时候肯定须要留神案值传递导致的复制问题。(须要留神的是 Go 中的 struct 只能定义字段,不能定义函数。)

// struct 的定义是配合 type 关键字一起应用的

type People struct {

name string // 定义的字段和 Go 语言其余的格调雷同,名字在前,类型在后

age int

}

2.2Go 与 C# 不一样但应用办法差不多的关键字

  • package
  • import
  • type
  • defer

2.2.1.Package 与 namespace

Go 中的 package 和 C#的 namespace 基本相同,就是定义组织的一个包,次要作用是对代码模块进行隔离。但 Go 和 C#不同的是,C#非常灵便,即便不在一个文件夹下的代码都能够定义为雷同的 namespace。然而 Go 中 package 内的文件都须要在雷同的文件夹内能力被正确编译,并且一个文件夹内只能呈现最多一个包名。除此之外,相似于 C# 中的 Main 办法,Go 中可运行程序的执行入口也是一个 main 函数,然而 main 函数必须定义在 package main 下。

// Go 中,同一个文件夹只能同时存在一个包名

// 包名能够和文件夹名不同,然而必须有且只有一个

package main

// main 函数只能在 main 包下能力正确作为启动函数运行

func main() {//do something}

// 同文件夹下的另一个文件,比方 hello.go

package hello // 编译器报错

2.2.2.Import 与 using

Import 和 using 的作用都是用来导入其余模块的代码。然而 Go 比 C# 多了一个强制要求:没有在代码模块中应用 import 或者是定义了然而没有应用的变量,在编译时会间接报错。这样做的目标除了使代码看起来更简洁以外,最次要的起因是 import 语句还有另一个重要性能就是调用包中的 init()函数。例如如下代码:

// hello 文件夹下的 demo 文件夹内的 demo.go

package demo

var me string

func init() {me = "jeffery"}

func SayHello() {fmt.Printf("hello, %s", me)

}

// hello 文件夹下的 hello.go

package main

import "hello/demo"

func main() {demo.SayHello() // 输入:hello, jeffery

}

上述的程序定义了一个 demo 文件,当 demo 文件第一次被 import 关键字加载到其余包时,会主动调用其 init()函数,这时就会把变量 me 赋值为 jeffery,之后调用 SayHello()函数时,返回的就都是”hello, jeffery”了。也正是因为 init 函数的存在,不应用的 import 须要被删除,因为如果不删除很有可能会主动调用到未被应用的包内的 init 函数。

2.2.3. Type 与 class

  • 惯例用法

把 type 和 class 比照其实是不太正当的。因为 C# 中 class 关键字是定义一个类型和这个类型的具体实现,比方下述的代码在 C# 中的意思是定义一个名为 People 的类,并且定义了这类中有一个属性 Age。

interface IAnimal {public void Move();

}

class People {public int Age { get;set;}

}

然而 Go 中的 type 关键字仅仅是用来定义类型名称的,如果想要定义其实现,必须前面再更上具体实现的关键字。比方上述的代码定义在 Go 中就变成了如下:

type IAnimal interface {Move()

}

type People struct {Age int}

上述只是 type 的最罕用用法,除此之外 type 还有两个其余的用法:

  • 以一个基准类型定义一个新类型
type Human People

这样的语句相当于用 People 类型定义了一个 Human 的新类型。留神,这里是一个新类型,而不是 C# 中的继承 。因而如果 People 内有一个 Move 函数,那 Human 对象是无奈调用这个 Move 函数的,如果非要应用,则须要强制类型转换。(Go 中的强制类型转换是类型 + (),比方上述的例子 Human(People) 就能够把 People 类型强转为 Human 类型)

  • 定义类型别名
type Human = People

如果应用了等号进行定义,那就相当于给类型 People 定义了一个别名 Human,这种状况下 People 中的代码 Human 也是能够失常应用的。下面两种用法根本都不罕用,这里只做理解即可。

2.2.4.Defer 与 finally

Go 中的 defer 和 C# 的 finally 是一样的,在一个办法执行完结退出之前只能够干一件事。而和 C# 不太一样的是,Go 中的 defer 语句不必必须写在最初,比方咱们会常常看到这样格调的代码:

var mutex sync.Mutex // 一个全局锁,能够相似的等价于 C# 中的 Monitor 类

func do() {mutex.Lock()

defer mutex.Unlock()

// ...

}

下面这个例子的意思是定义一个全局锁,在 do 函数进入时,加锁,在退出时解锁。之后再去写本人的业务逻辑。除此之外,defer 也能够写多个,但最终的执行程序是从下向上执行,也就是最初定义的 defer 先执行。

2.3Go 有而 C# 没有的关键字

  • fallthrough
  • func

    2.3.1. Fallthrough

这个关键字是为了兼容 C 语言中的 fallthrough,其目标是是在 switch-case 语句中再向下跳一个 case,比方上面这个例子:

switch n := "a"; n {

case n == "a":

fmt.Println("a")

fallthrough

case n == "b":

fmt.Println("b")

case n == "c":

fmt.Println("c")

}

这个例子的最终输入后果就是:

a

b

2.3.2.Func

和其余函数(比方 JavaScript 的 function,Python 中的 def)一样,Go 中的 func 就是用来定义函数的。

// 定义了一个函数名称为 getName 的函数

// 其中蕴含一个 int 类型的参数 id

// 以及两个返回值,string 和 bool 类型

func getName(id int) (string, bool) {return "jeffery", true}

Go 中的函数以及其余一系列须要定义类型的语法中,永远都遵循 名称在前,类型在后。此外,Go 中的 func 同样也能够配合 type 应用定义 C# 中的委托,比方咱们能够在 C# 中定义一个.Net Core 的中间件:

public delegate void handleFunc(HttpContext httpContext);

public delegate handleFunc middleware(handleFunc next);

这样的代码能够在 Go 中这样实现:

type handleFunc func(httpContext HttpContext)

type middleware func(next handleFunc) handleFunc

3. 文章小结

Go 语言相较于 C# 在关键字上的长处有以下几个:

1. 更简洁的语法:Go 语言致力于简化代码的编写和了解,使得语言关键字的数量更少,更加简洁明了。相比之下,C# 领有更多的关键字,从而使代码的可读性略微升高。

2. 更好的并发性反对:Go 语言人造反对并发编程,通过 goroutine 和 channel 管道,能够轻松实现高并发的程序。而 C# 对于并发编程须要手动解决锁,信号量等机制来控制线程的并发,代码比拟繁琐。

3. 更好的内存治理:Go 语言应用垃圾回收机制,不须要开发者手动治理内存,防止了许多内存透露等问题。相比之下,C# 须要开发者手动进行内存治理,须要应用 using 关键字或者手动开释内存等机制来管制内存,这减少了代码的复杂性。

4. 更好的性能:因为采纳了更简洁的语法和更好的内存治理,Go 语言编写的程序具备更好的性能体现。与 C# 相比,Go 语言的程序不仅运行速度更快,而且资源耗费更少,性能更杰出。

4. 扩大链接

如何应用 Blazor 框架在前端浏览器中导入 / 导出 Excel XLSX

万物皆可集成系列:低代码对接微信小程序

C# 编写服务器端 API

正文完
 0