Go语言在云计算、边缘计算、大数据、微服务、物联网、高并发领域应用得越来越广泛,越来越多的知名公司正在把Go作为开发新项目的首选语言,golanguage主要在如下场景中有着广泛的应用:
Google在创造Go的原因:
从C语言中继承了很多理念,包括表达式语法,控制结构,基础数据类型,调用参数传值,指针等等,也保留了和C语言一样的编译执行方式及弱化的指针。
引入包的概念,用于组织程序结构,GO的语言一个文件都要归属一个包,而不能单独存在。
垃圾回收机制,内存自动回收,不需要开发人员管理
天然并发(重要特点)
从语言层面支持并发,实现简单
goroutine,轻量级线程,可实现大并发处理,高效利用多核。
基于GPS并发模型(Communicating Sequential Processes)实现
吸收了管道通信机制,形成GO语言特有的管道channel通过管道channel,可以实现不同的goroute之间的相互通信
函数可以返回多个值
新的创新:比如切片slice、延时执行defer等
什么是静态语言?
类型 | 原理 | 优点 | 缺点 |
---|---|---|---|
静态语言 | 静态语言是指在编译期间对数据类型进行检查的语言。这种语言在编写程序时需要声明所有变量的数据类型。典型的静态语言如C,C++、Java。 | 1. 由于类型的强制声明,使得IDE有很强的代码感知能力,在实现复杂的业务逻辑、开发大型商业系统、以及那些生命周期很长的应用中,依托IDE对系统的开发很有保障;2. 由于静态语言相对比较封闭,使得第三方开发包对代码的侵害性可以降到最低。 | |
动态语言 | 动态语言是指在运行期间才去做数据类型检测的语言。在用动态语言编程的时候并不需要给变量指定数据类型,该语言会在第一次将数据赋值给变量的时候在内部将数。据类型记录下来。典型的动态语言如Python,Ruby。 | 1. 思维不受束缚,可以任意发挥,把更多的精力放在产品本身上;2. 集中思考业务逻辑实现,思考过程即实现过程。 |
什么是编译型的语言?
类型 | 原理 | 优点 | 缺点 |
---|---|---|---|
编译型语言 | 通过专门的编译器,将所有源代码一次性转换成特定平台(Windows、Linux 等)执行的机器码(以可执行文件的形式存在)。 | 编译一次后,脱离了编译器也可以运行,并且运行效率高。 | 可移植性差,不够灵活。 |
解释型语言 | 由专门的解释器,根据需要将部分源代码临时转换成特定平台的机器码。 | 跨平台性好,通过不同的解释器,将相同的源代码解释成不同平台下的机器码。 | 一边执行一边转换,效率很低。 |
内置并发编程支持
内置了映射(map)和切片(slice)类型
支持多态(polumorphism)
类的多态特性,还要满足以下 2 个前提条件:
pythonclass CLanguage:
def say(self):
print("调用的是 Clanguage 类的say方法")
class CPython(CLanguage):
def say(self):
print("调用的是 CPython 类的say方法")
class CLinux(CLanguage):
def say(self):
print("调用的是 CLinux 类的say方法")
a = CLanguage()
a.say()
a = CPython()
a.say()
a = CLinux()
a.say()
程序执行结果为:
调用的是 Clanguage 类的say方法 调用的是 CPython 类的say方法 调用的是 CLinux 类的say方法
可以看到,CPython 和 CLinux 都继承自 CLanguage 类,且各自都重写了父类的 say() 方法。从运行结果可以看出,同一变量 a 在执行同一个 say() 方法时,由于 a 实际表示不同的类实例对象,因此 a.say() 调用的并不是同一个类中的 say() 方法,这就是多态。
defer语句通常用于一些成对操作的场景:打开连接/关闭连接;加锁/释放锁;打开文件/关闭文件等。 9. 支持类型内嵌(type embedding) 结构体允许其成员字段在声明时没有字段名,而只有类型。这种形式的字段称为匿名字段或类型内嵌。
最简单的go程序,test.go
gopackage main
import "fmt"
func main(){
fmt.Println("hello, world")
}
在此程序中,单词package和func是两个关键字。两个main是两个标识符
go run test.go
输出:
EricDeMac:第一天 eric$ go run test.go hello world
如果一个程序的main包中有若干Go源代码文件,我们也可以使用下面的命令运行此程序。
go run .
注意
gopackage main // 指定当前源文件所在的包名
import "math/rand" // 引入一个标准库包
const MaxRand = 16 // 声明一个具名整型常量
// 一个函数声明
/*
StatRandomNumbers生成一些不大于MaxRand的非负
随机整数,并统计和返回小于和大于MaxRand/2的随机数
个数。输入参数numRands指定了要生成的随机数的总数。
*/
func StatRandomNumbers(numRands int) (int, int) {
// 声明了两个变量(类型都为int,初始值都为0)
var a, b int
// 一个for循环代码块
for i := 0; i < numRands; i++ {
// 一个if-else条件控制代码块
if rand.Intn(MaxRand) < MaxRand/2 {
a = a + 1
} else {
b++ // 等价于:b = b + 1
}
}
return a, b // 此函数返回两个结果
}
// main函数,或主函数,是一个程序的入口函数。
func main() {
var num = 100
// 调用上面声明的StatRandomNumbers函数,
// 并将结果赋给使用短声明语句声明的两个变量。
x, y := StatRandomNumbers(num)
// 调用两个内置函数(print和println)。
print("Result: ", x, " + ", y, " = ", num, "? ")
println(x+y == num)
}
像很多其它流行编程语言一样,Go也使用一对大括号{ and }来形成一个显式代码块。但是在Go代码中,编码样式风格有一些限制。 比如,很多左大括号{不能被放到下一行。 如果,上面的StatRandomNumbers被修改成如下所示,则上面的示例程序将编译不通过。
go
// 编译错误
func StatRandomNumbers(numRands int) (int, int)
{ // 编译错误:语法错误
var a, b int
for i := 0; i < numRands; i++
{ // 编译错误:语法错误
if rand.Intn(MaxRand) < MaxRand/2
{ // 编译错误:语法错误
a = a + 1
} else {
b++
}
}
return a, b
}
go中共有25个关键字
shellbreak default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
这些关键字可以分为四组:
一个标识符是一个以Unicode字母或者_开头并且完全由Unicode字母和Unicode数字组成的单词。
标识符_是一个特殊字符,它叫做空标识符。
以后,我们将知道所有的类型名、变量名、常量名、跳转标签、包名和包的引入名都必须是标识符。
一个由Unicode大写字母开头的标识符称为导出标识符。 这里导出可以被理解为公开(public)。 其它(即非Unicode大写字母开头的)标识符称为非导出标识符。 非导出可以被理解为私有(private)。 截至目前(Go 1.20),东方字符都被视为非导出字符。 非导出有时候也被称为未导出。
下面是一些合法的导出标识符:
Player_9 DoSomething VERSION Ĝo Π
下面是一些合法的未导出标识符:
_ _status memStat book π 一个类型 변수 エラー
下面这些不能被用做标识符:
// Unicode数字开头 123 3apples // 含有不符合要求的Unicode字符 a.b *ptr $name a@b.c // 这两个是关键字 type range
Go支持如下内置基本类型:
Go中有两种内置类型别名(type alias):
以u开头的整数类型称为无符号整数类型。 无符号整数类型的值都是非负的。 一个数值类型名称中的数字表示每个这个类型的值将在内存中占有多少二进制位(以后简称位)。二进制位常称为比特(bit)。 比如,一个uint8的值将占有8位。 我们称uint8类型的值的尺寸是8位。 因此,最大的uint8值是255(28-1), 最大的int8值是127(27-1), 最小的int8值是-128(-27)。
下面是一个类型声明的例子。 在这些例子中,type是一个关键字。
go// 一些类型定义声明
type status bool // status和bool是两个不同的类型
type MyString string // MyString和string是两个不同的类型
type Id uint64 // Id和uint64是两个不同的类型
type real float32 // real和float32是两个不同的类型
// 一些类型别名声明
type boolean = bool // boolean和bool表示同一个类型
type Text = string // Text和string表示同一个类型
type U8 = uint8 // U8、uint8和 byte表示同一个类型
type char = rune // char、rune和int32表示同一个类型
我们将上面定义的real类型和内置类型float32都称为float32类型 (注意这里的第二个float32是一个泛指,而第一个高亮的float32是一个特指)。 同样地,MyString和string都被称为字符串(string)类型,status和bool都被称为布尔(bool)类型。
每种类型都有一个零值。一个类型的零值可以看作是此类型的默认值。
Go白皮书没有定义布尔类型值字面量形式。 我们可以将false和true这两个预声明的具名常量当作布尔类型的字面量形式。 但是,我们应该知道,从严格意义上说,它们不属于字面量。具名常量声明将在下一篇文章中介绍和详细解释。
布尔类型的零值可以使用预声明的false来表示。
go0xF // 十六进制表示(必须使用0x或者0X开头)
0XF
017 // 八进制表示(必须使用0、0o或者0O开头)
0o17
0O17
0b1111 // 二进制表示(必须使用0b或者0B开头)
0B1111
15 // 十进制表示(必须不能用0开头)
下面的程序打印出两个true。
gopackage main
func main() {
println(15 == 017) // true
println(15 == 0xF) // true
}
一个浮点数的完整十进制字面量形式可能包含一个十进制整数部分、一个小数点、一个十进制小数部分和一个以10为底数的整数指数部分。 整数指数部分由字母e或者E带一个十进制的整数字面量组成(xEn表示x乘以10n的意思,而xE-n表示x除以10n的意思)。 常常地,某些部分可以根据情况省略掉。一些例子:
go1.23
01.23 // == 1.23
.23
1.
// 一个e或者E随后的数值是指数值(底数为10)。
// 指数值必须为一个可以带符号的十进制整数字面量。
1.23e2 // == 123.0
123E2 // == 12300.0
123.E+2 // == 12300.0
1e-1 // == 0.1
.1e0 // == 0.1
0010e-2 // == 0.1
0e+5 // == 0.0
从Go 1.13开始,Go也支持另一种浮点数字面量形式:十六进制浮点数字面量。 在一个十六进制浮点数字面量中,
一些合法的浮点数的十六进制字面量例子:
go0x1p-2 // == 1.0/4 = 0.25
0x2.p10 // == 2.0 * 1024 == 2048.0
0x1.Fp+0 // == 1+15.0/16 == 1.9375
0X.8p1 // == 8.0/16 * 2 == 1.0
0X1FFFP-16 // == 0.1249847412109375
一个虚部值的字面量形式由一个浮点数字面量或者一个整数字面量和其后跟随的一个小写的字母i组成。 在Go 1.13之前,如果虚部中i前的部分为一个整数字面量,则其必须为并且总是被视为十进制形式。 一些例子:
go1.23i
1.i
.23i
123i
0123i // == 123i(兼容性使然。见下)
1.23E2i // == 123i
1e-1i
011i // == 11i(兼容性使然。见下)
00011i // == 11i(兼容性使然。见下)
// 下面这几行从Go 1.13开始才能编译通过。
0o11i // == 9i
0x11i // == 17i
0b11i // == 3i
0X.8p-0i // == 0.5i
从Go 1.13开始,下划线_可以出现在整数、浮点数和虚部数字面量中,以用做分段符以增强可读性。 但是要注意,在一个数值字面表示中,一个下划线_不能出现在此字面表示的首尾,并且其两侧的字符必须为(相应进制的)数字字符或者进制表示头。
一些合法和不合法使用下划线的例子:
go// 合法的使用下划线的例子
6_9 // == 69
0_33_77_22 // == 0337722
0x_Bad_Face // == 0xBadFace
0X_1F_FFP-16 // == 0X1FFFP-16
0b1011_0111 + 0xA_B.Fp2i
// 非法的使用下划线的例子
_69 // 下划线不能出现在首尾
69_ // 下划线不能出现在首尾
6__9 // 下划线不能相连
0_xBadFace // x不是一个合法的八进制数字
1_.5 // .不是一个合法的十进制数字
1._5 // .不是一个合法的十进制数字
go'a' // 一个英文字符
'π'
'众' // 一个中文字符
'\141' // 141是97的八进制表示
'\x61' // 61是97的十六进制表示
'\u0061'
'\U00000061'
gopackage main
func main() {
println('a' == 97)
println('a' == '\141')
println('a' == '\x61')
println('a' == '\u0061')
println('a' == '\U00000061')
println(0x61 == '\x61')
println('\u4f17' == '众')
}
本文作者:Eric
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!