一、基本情况
1.1、Golang基本介绍
Go语言(或 Golang)起源于 2007 年,并在 2009 年正式对外发布。Go 是非常年轻的一门语言,它的主要目标是“兼具 Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性”。
Go语言的推出,旨在不损失应用程序性能的情况下降低代码的复杂性,具有“部署简单、并发性好、语言设计良好、执行性能好”等优势,目前国内诸多 IT 公司均已采用Go语言开发项目。
Go语言有时候被描述为“C 类似语言”,或者是“21 世纪的C语言”。Go 从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等很多思想,还有C语言一直所看中的编译后机器码的运行效率以及和现有操作系统的无缝适配。
因为Go语言没有类和继承的概念,所以它和 Java 或 C++ 看起来并不相同。但是它通过接口(interface)的概念来实现多态性。Go语言有一个清晰易懂的轻量级类型系统,在类型之间也没有层级之说。因此可以说Go语言是一门混合型的语言。
此外,很多重要的开源项目都是使用Go语言开发的,其中包括 Docker、Go-Ethereum、Thrraform 和 Kubernetes。
据最新的2020年9月Tiobe编程语言排行榜,目前Golang的使用率排名为第11:
1.2、Golang使用场景
- 服务端开发(配合gin、gorm等库就能够完成高性能的后端服务)
- 容器开发(譬如Docker、K8s都是基于Golang开发的)
- 脚本开发(由于Golang自身部署简单,并且与操作系统API交互方便,所以还可替代Python作为脚本开发)
- 底层工具的开发(可代替C或者C++开发操作系统底层工具)
二、基本语法
2.1、编码规约
Golang是一门严格的工程语言,主要体现在编码风格及可见域规则上。在Java中,允许多种编码风格共存,譬如以下两种方法声明,对于Java来说都是允许的:
1 | java复制代码public String getString(Integer num) { |
1.左右花括号需要符合上下换行风格
在Golang中,只允许出现一种换行风格:
1 | go复制代码func getString(num int) string { |
如果出现以下换行风格则会报错,无法通过编译:
2.变量声明后必须使用,不使用需要使用_来代替
在Java中,变量可以声明了却不使用,而Golang中声明的变量必须被使用,否则需要使用_来替代掉变量名,表明该变量不会比使用到:
1 | go复制代码func getString(num int) string { |
3.可见域规则
Java对方法、变量及类的可见域规则是通过private、protected、public关键字来控制的,而Golang中控制可见域的方式只有一个,当字段首字母开头是大写时说明其是对外可见的、小写时只对包内成员可见。
- entity
1 | go复制代码package entity |
- main
1 | go复制代码package main |
2.2、变量声明及初始化
1.变量声明及初始化的文法
在Java中,通常声明变量及初始化的文法为:
1 | java复制代码 // Object:要声明的类型、v:变量名称、new Object()变量初始化 |
而Golang使用var关键字来声明变量:
1 | go复制代码 // var:变量定义、v1:变量名称、int:变量类型 |
也可以采用:=自动推测变量类型:
1 | go复制代码 var v1 int = 10 // 正确的使用方式1 |
2.对于基本类型,声明即初始化;对于引用类型,声明则初始化为nil
在Java中,如果在方法内部声明一个变量但不初始化,在使用时会出现编译错误:
1 | java复制代码public void solve() { |
而在Golang中,对于基本类型来讲,声明即初始化;对于引用类型,声明则初始化为nil。这样可以极大地避免NPE的发生。
1 | go复制代码func main() { |
2.3、值类型及引用类型
Golang的类型系统与Java相差不大,但是需要注意的是Java中的数组是属于引用类型,而Golang中的数组属于值类型,当向方法中传递数组时,Java可以直接通过该传入的数组修改原数组内部值(浅拷贝),但Golang则会完全复制出一份副本来进行修改(深拷贝):
- Java
1 | java复制代码 public static void main(String[] args) { |
- Golang
1 | go复制代码func main() { |
并且值得注意的是,在Golang中,只有同长度、同类型的数组才可视为“同一类型”,譬如[2]int和[3]int则会被视为不同的类型,这在参数传递的时候会造成编译错误。
所以在Golang中数组很少被直接使用,更多的是使用切片(基于数组指针)来代替数组。
在Golang中,只有切片、指针、channel、map及func属于引用类型,也就是在传递参数的时候,实质上复制的都是他们的指针,内部的修改会直接影响到外部:
1 | go复制代码func main() { |
三、结构体、函数及指针
3.1、结构体声明及使用
在Golang中区别与Java最显著的一点是,Golang不存在“类”这个概念,组织数据实体的结构在Golang中被称为结构体。函数可以脱离“类”而存在,函数可以依赖于结构体来调用或者依赖于包名调用。
Golang中的结构体放弃了继承、实现等多态概念,结构体之间可使用组合来达到复用方法或者字段的效果。
要声明一个结构体只需使用type + struct关键字即可:
1 | go复制代码type Person struct { |
要使用一个结构体也很简单,一般有以下几种方式去创建结构体:
1 | go复制代码 personPoint := new(entity.Person) // 通过new方法创建结构体指针 |
3.2、函数和方法的区别
使用Java的朋友应该很少使用“函数”这个词,因为对于Java来说,所有的“函数”都是基于“类”这个概念构建的,也就是只有在“类”中才会包含所谓的“函数”,这里的“函数”被称为“方法”。
而“函数”这个词源于面向过程的语言,所以在Golang中,“函数”和“方法”的最基本区别是:
函数不基于结构体而是基于包名调用,方法基于结构体调用。
下面是一个例子,可以直观地看出方法和函数的区别:
- entity
1 | go复制代码package entity |
- main
1 | go复制代码func main() { |
3.3、指针的使用
在Java中不存在显式的指针操作,而Golang中存在显式的指针操作,但是Golang的指针不像C那么复杂,不能进行指针运算。
下面从一个例子来看Java的隐式指针转化和Golang的显式指针转换:Java和Golang方法传参时传递的都是值类型,在Java中如果传递了引用类型(对象、数组等)会复制其指针进行传递, 而在Golang中必须要显式传递Person的指针,不然只是传递了该对象的一个副本。
Golang使用 * 来定义和声明指针,通过&来取得对象的指针。
1 | go复制代码func main() { |
注意,如果结构体中需要组合其他结构体,那么建议采用指针的方式去声明,否则会出现更新丢失问题。
以下是Golang方法的一个隐式指针转换,结构体调用方法时,如果传递的是对象,那么会被自动转化为指针调用:
1 | go复制代码 |
本文转载自: 掘金