前言
这两年主流的编程语言 Golang,想必大家或多或少都接触过。云原生领域的许多组件都基于Go开发的,例如Docker,Kubernetes,etcd,还有很多大厂的新业务都转向了Go。
所以,对于程序员而言,掌握Go语言就显得尤为重要,尤其是Java程序员(懂得都懂)。希望通过本文的介绍,Java开发者可以快速入门Go语言。
一个 go 文件长啥样?
最简单的Hello,World:
跟 java 文件不同,go文件中的包名(package)跟文件路径没有关系,即便文件所在的路径是aa/bb/cc
,包名也可以是xx
,但是 main 函数必须在 main 包。
func
是声明函数的关键字,main
函数就类似Java的main
方法,程序的执行入口,写法有点像js。
导入包有两种方式
go
导入单个包
import "fmt"
导入多个包
import (
"fmt"
"os"
)
Go 语言的变量
入门一个编程语言,个人认为先要了解基本的变量类型和变量的定义,其他的运算符、控制流语句都大差不差。
变量类型
Go 语言变量类型可以分为两大类:基本类型和派生类型。
类型 | 变量类型 | 描述 |
---|---|---|
基本类型 | 布尔型 (bool ) |
逻辑值,true 或 false |
整数型 | ||
int8 |
8位有符号整数 | |
int16 |
16位有符号整数 | |
int32 |
32位有符号整数 | |
int64 |
64位有符号整数 | |
uint8 (别名 byte ) |
8位无符号整数,通常用于表示ASCII字符 | |
uint16 |
16位无符号整数 | |
uint32 |
32位无符号整数 | |
uint64 |
64位无符号整数 | |
rune (别名 int32 ) |
用于表示Unicode码点 | |
浮点型 | ||
float32 |
32位IEEE 754浮点数 | |
float64 |
64位IEEE 754浮点数 | |
complex64 |
32 位实数和虚数 | |
complex128 |
64 位实数和虚数 | |
字符串型 (string ) |
文本数据 | |
派生类型 | 数组 | 固定数量的同一类型的元素 |
切片 | 动态大小的、灵活的、可变的数组,类似Java中的List | |
映射 (Map) | 无序的键值对集合 | |
结构体 (Struct) | 用户定义的类型,包含多个字段,类似Java中的类 | |
指针 (*T ) |
存储一个变量的内存地址 | |
通道 (Chan) | 用于在goroutines之间进行通信 | |
函数 (func ) |
可执行的代码块 | |
接口 (Interface) | 定义对象的一组方法集 |
其中Struct可以理解为Java中的一个类,定义一些成员变量,而且仅限变量。
指针是Java中没有的类型,Go 语言中的指针可以直接对变量所在的内存进行访问和操作。这就意味着,如果一个函数接收的参数是指针类型,就会像Java的引用传递一样。如下示例
通道是用于协程之间通信的,后面有代码示例。
变量声明
和Java相比,Go 语言中声明变量时,变量名称在变量类型的前面,如下:
go
var num int = 1
Go 语言声明变量有两种方式:
- 显式声明:使用 var 关键字,并根据实际情况指定变量类型。如:
go
var num int = 1
var num = 1 //编译器会根据初始化值推断变量的类型
var num int //声明变量不初始化,必须要指定变量类型
- 类型推断:使用:=操作符,编译器会自动推断出变量类型(体现出简洁的特性)。如:
go
num:=1
如果声明了一个变量但没有使用它,编译器会报一个错误,提示该变量是多余的。这是 Go 语言的一个特性。
Go 语言的函数&方法
Go 语言中的函数和方法,都是用 func 关键字定义的,但是使用场景不同。两者定义如下:
函数是独立定义的代码块,不依赖任何类型。格式如下:
但是 Go 语言不支持同名但参数列表不同的函数,也就是重载。
方法是定义在某个类型的函数,通常是结构体,所以声明方法时需要关联结构体。格式如下:
结构体中只能声明变量,不能声明函数。所以给一个结构体定义一个函数,就需要通过这种方式。例如 Java 中的 getter 方法在 Go 语言中这样声明:
函数和方法的区别就是调用对象不同,函数不属于任何类型,方法属于某个类型。
Go 语言没有的概念
- 没有修饰符,比如 private、public。
- 没有类、封装、继承、多态等面向对象概念。
- 没有异常,比如 try...catch...。
虽然没有这些概念,但是可以通过其他方式呈现。
访问修饰符
Go 语言中没有直接提供类似 Java 中的访问修饰符(public、private、protected
)来控制成员的可见性,但是可以通过命名规定实现类似的效果。
如果一个标识符(变量、函数、类型等)的首字母是大写 的,那么对其他包是可见的 。如果首字母是小写 的,那么它就只能在内部访问。
例如下面的示例中,ExportedVariable
可以被外部的包进行访问,而unexportedVariable
就不可以。
面向对象模型
Go 语言中没有直接提供类似 Java 中的类和继承面向对象编程模型,但它可以通过一种更简洁和直接的方式实现封装、继承和多态这些概念。
下面是一个简单的示例,通过结构体、接口和方法实现面向对象。
在结构体Rectangle嵌入BaseShape,就相当于继承,也可以是ORM中的一对一关系。
给Rectangle定义的Area方法就相当于封装。
而Go 语言中的接口实现,不像结构体和方法那样有显式的关联。结构体和接口的关系是这样的:如果某个结构体实现了接口中定义的所有方法,那么它就被认为实现了该接口,例如上面示例中的Area() 。
异常处理机制
Go 语言中没有 Java 中的异常处理机制,也就是try...catch...
,而是以返回值的方式将错误返回给调用方,如下面的示例:
Go 语言高效简洁的并发编程
Go 语言的并发编程是它的一大特色,和 Java 并发线程不同的是,Go 采用轻量级的协程(Goroutine)实现并发程序,协程之间的通信通过通道机制实现。下面是一个简单的示例
相比 Java 复杂的并发编程,Go 语言显得特别的简单。
总结
基于 Go 语言编写的代码整体看上去是非常简洁的,而且语法规则和关键字相对较少,对于小白来说也比较容易上手。