• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Go初探

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
 

官方网站:https://golang.org/
标准库文档:https://golang.org/pkg/
在线编码学习:https://play.golang.org/
PS:请自行FQ


(大家好,我是go吉祥物,地鼠君)

Go语言是谷歌推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发Go,是因为过去10多年间软件开发的难度令人沮丧。

Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人(真是豪门出身),并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。

Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。

Go的目标是希望提升现有编程语言对程序库等依赖性(dependency)的管理,这些软件元素会被应用程序反复调用。由于存在并行编程模式,因此这一语言也被设计用来解决多处理器的任务。

如果第一次接触Go语言,更像是对c语言的修补和延伸。

特性

  • 编译型语言,执行效率接近c/c++,可以编译成机器码,不依赖其他库
  • 自动垃圾回收
  • 更丰富的内置类型和自动类型推导(类似c++11的auto)
  • 函数可以返回多个值
  • 拥有更好的错误处理
  • 匿名函数和闭包
  • 支持类型和接口
  • 并发编程
  • 支持反射机制
  • 语言交互性强
  • 工程依赖自动推导
  • 打包和部署容易

安装

$ sudo apt-get install golang
$ sudo apt-get install gccgo
$ go version
go version go1.2.1 linux/amd64

 

Hello World 实例

  1. package main
  2. import"fmt"
  3. func main(){
  4. /* 这是我的第一个简单的程序 */
  5. fmt.Println("Hello, World!")
  6. }
  7. //执行
  8. $ go run hello.go
  9. Hello,World!

编译

Go是一个编译型的语言。目前有两种编译器,其中”Gccgo”采用GCC作为编译后端。另外还有 根据处理器架构命名的编译器:针对64位x86结构为”6g”,针对32位x86结构的为”8g”等等。 这些go专用的编译器编译很快,但是产生的目标代码效率比gccgo稍差一点。

$ 6g helloworld.go # 编译; 输出 helloworld.6
$ 6l helloworld.6 # 链接; 输出 6.out
$ 6.out
Hello, world!
$
$ gccgo helloworld.go
$ a.out
Hello, world!
$

基础语法

行分隔符

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。

  1. fmt.Println("Hello, World!")
  2. fmt.Println("w3cschool菜鸟教程:w3cschool.cc")
  3. fmt.Println("Hello, World!");fmt.Println("w3cschool菜鸟教程:w3cschool.cc")

注释

注释不会被编译,每一个包应该有相关注释。
单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾。如:

  1. // 单行注释
  2. /*
  3. Author by w3cschool菜鸟教程
  4. 我是多行注释
  5. */

标识符

标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。

关键字

下面列举了 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 语言还有 36 个预定义标识符:
append bool byte cap close complex complex64 complex128 uint16
copy false float32 float64 imag int int8 int16 uint32
int32 int64 iota len make new nil panic uint64
print println real recover string true uint uint8 uintptr
程序一般由关键字、常量、变量、运算符、类型和函数组成。
程序中可能会使用到这些分隔符:括号 (),中括号 [] 和大括号 {}。
程序中可能会使用到这些标点符号:.、,、;、: 和 …。

数据类型

在 Go 编程语言中,数据类型用于声明函数和变量。
数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。

布尔型
布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。

数字类型
整型 int 和浮点型 float,Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码。
uint8
无符号 8 位整型 (0 到 255)
uint16
无符号 16 位整型 (0 到 65535)
uint32
无符号 32 位整型 (0 到 4294967295)
uint64
无符号 64 位整型 (0 到 18446744073709551615)
int8
有符号 8 位整型 (-128 到 127)
int16
有符号 16 位整型 (-32768 到 32767)
int32
有符号 32 位整型 (-2147483648 到 2147483647)
int64
有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
float32
IEEE-754 32位浮点型数
float64
IEEE-754 64位浮点型数
complex64
32 位实数和虚数
complex128
64 位实数和虚数
byte
类似 uint8
rune
类似 int32
uint
32 或 64 位
int
与 uint 一样大小
uintptr
无符号整型,用于存放一个指针

字符串类型:
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本。

指针类型(Pointer)

Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。
接下来让我们来一步步学习 Go 语言指针。
我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址。
类似于变量和常量,在使用指针前你需要声明指针。
在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。

  1. package main
  2. import"fmt"
  3. func main(){
  4. var a int=20/* 声明实际变量 */
  5. var ip *int/* 声明指针变量 */
  6. ip =&a /* 指针变量的存储地址 */
  7. fmt.Printf("a 变量的地址是: %x\n",&a )
  8. /* 指针变量的存储地址 */
  9. fmt.Printf("ip 变量的存储地址: %x\n", ip )
  10. /* 使用指针访问值 */
  11. fmt.Printf("*ip 变量的值: %d\n",*ip )
  12. }

当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
一个指针变量通常缩写为 ptr。

  1. if(ptr !=nil)/* ptr 不是空指针 */
  2. if(ptr ==nil)/* ptr 是空指针 */

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。
当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:

  1. package main
  2. import"fmt"
  3. func main(){
  4. var a int
  5. var ptr *int
  6. var pptr **int
  7. a =3000
  8. /* 指针 ptr 地址 */
  9. ptr =&a
  10. /* 指向指针 ptr 地址 */
  11. pptr =&ptr
  12. /* 获取 pptr 的值 */
  13. fmt.Printf("变量 a = %d\n", a )
  14. fmt.Printf("指针变量 *ptr = %d\n",*ptr )
  15. fmt.Printf("指向指针的指针变量 **pptr = %d\n",**pptr)
  16. }

数组(Array)

  1. package main
  2. import"fmt"
  3. func main(){
  4. var n [10]int/* n 是一个长度为 10 的数组 */
  5. var i,j int
  6. /* 为数组 n 初始化元素 */
  7. for i =0; i <10; i++{
  8. n[i]= i +100/* 设置元素为 i + 100 */
  9. }
  10. /* 输出每个数组元素的值 */
  11. for j =0; j <10; j++{
  12. fmt.Printf("Element[%d] = %d\n", j, n[j])
  13. }
  14. }

结构化类型(struct)

Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
Go语言的结构体(struct)和其它语言的类(class)有同等的地位。但Go语言放弃了包括继承在内的大量OOP特性,只保留了组合(compose)这个最基础的特性。
所有的Go语言的类型(指针类型除外)都是可以有自己的方法。在这个背景下,Go语言的结构体(struct)它只是很普通的复合类型

  1. package main
  2. import"fmt"
  3. type Booksstruct{
  4. title string
  5. author string
  6. subject string
  7. book_id int
  8. }
  9. func main(){
  10. varBook1Books/* 声明 Book1 为 Books 类型 */
  11. varBook2Books/* 声明 Book2 为 Books 类型 */
  12. /* book 1 描述 */
  13. Book1.title ="Go 语言"
  14. Book1.author ="www.runoob.com"
  15. Book1.subject ="Go 语言教程"
  16. Book1.book_id =6495407
  17. /* book 2 描述 */
  18. Book2.title ="Python 教程"
  19. Book2.author ="www.runoob.com"
  20. Book2.subject ="Python 语言教程"
  21. Book2.book_id =6495700
  22. /* 打印 Book1 信息 */
  23. printBook(Book1)
  24. /* 打印 Book2 信息 */
  25. printBook(Book2)
  26. }
  27. func printBook( book Books){
  28. fmt.Printf("Book title : %s\n", book.title);
  29. fmt.Printf("Book author : %s\n", book.author);
  30. fmt.Printf("Book subject : %s\n", book.subject);
  31. fmt.Printf("Book book_id : %d\n", book.book_id);
  32. }

构造函数?不需要。在Go语言中你只需要定义一个普通的函数,只是通常以NewXXX来命名,表示“构造函数”:
“`go
func NewRect(x, y, width, height float64) *Rect {
return &Rect{x, y, width, height}
}

  1. 这一切非常自然,没有任何突兀之处。
  2. ##切片(Slice)
  3. Go语言切片是对数组的抽象。
  4. Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
  5. 切片是可索引的,并且可以由 len()方法获取长度。
  6. 切片提供了计算容量的方法 cap()可以测量切片最长可以达到多少。
  7. 一个切片在未初始化之前默认为nil,长度为0
  8. 可以通过设置下限及上限来设置截取切片[lower-bound:upper-bound]
  9. ```go
  10. package main
  11. import "fmt"
  12. func main() {
  13. /* 创建切片 */
  14. numbers := []int{0,1,2,3,4,5,6,7,8}
  15. printSlice(numbers)
  16. /* 打印原始切片 */
  17. fmt.Println("numbers ==", numbers)
  18. /* 打印子切片从索引1(包含) 到索引4(不包含)*/
  19. fmt.Println("numbers[1:4] ==", numbers[1:4])
  20. /* 默认下限为 0*/
  21. fmt.Println("numbers[:3] ==", numbers[:3])
  22. /* 默认上限为 len(s)*/
  23. fmt.Println("numbers[4:] ==", numbers[4:])
  24. numbers1 := make([]int,0,5)
  25. printSlice(numbers1)
  26. /* 打印子切片从索引 0(包含) 到索引 2(不包含) */
  27. number2 := numbers[:2]
  28. printSlice(number2)
  29. /* 打印子切片从索引 2(包含) 到索引 5(不包含) */
  30. number3 := numbers[2:5]
  31. printSlice(number3)
  32. }
  33. func printSlice(x []int){
  34. fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
  35. }
  36. /*len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
  37. numbers == [0 1 2 3 4 5 6 7 8]
  38. numbers[1:4] == [1 2 3]
  39. numbers[:3] == [0 1 2]
  40. numbers[4:] == [4 5 6 7 8]
  41. len=0 cap=5 slice=[]
  42. len=2 cap=9 slice=[0 1]
  43. len=3 cap=7 slice=[2 3 4]*/
  1. package main
  2. import"fmt"
  3. func main(){
  4. var numbers []int
  5. printSlice(numbers)
  6. /* 允许追加空切片 */
  7. numbers = append(numbers,0)
  8. printSlice(numbers)
  9. /* 向切片添加一个元素 */
  10. numbers = append(numbers,1)
  11. printSlice(numbers)
  12. /* 同时添加多个元素 */
  13. numbers = append(numbers,2,3,4)
  14. printSlice(numbers)
  15. /* 创建切片 numbers1 是之前切片的两倍容量*/
  16. numbers1 := make([]int, len(numbers),(cap(numbers))*2)
  17. /* 拷贝 numbers 的内容到 numbers1 */
  18. copy(numbers1,numbers)
  19. printSlice(numbers1)
  20. }
  21. func printSlice(x []int){
  22. fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
  23. }

接口类型(interface)

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

  1. package main
  2. import(
  3. "fmt"
  4. )
  5. type Phoneinterface{
  6. call()
  7. }
  8. type NokiaPhonestruct{
  9. }
  10. func (nokiaPhone NokiaPhone) call(){
  11. fmt.Println("I am Nokia, I can call you!")
  12. }
  13. type IPhonestruct{
  14. }
  15. func (iPhone IPhone) call(){
  16. fmt.Println("I am iPhone, I can call you!")
  17. }
  18. func main(){
  19. var phone Phone
  20. phone =new(NokiaPhone)
  21. phone.call()
  22. phone =new(IPhone)
  23. phone.call()
  24. }

Map 类型

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

  1. package main
  2. import"fmt"
  3. func main(){
  4. /* 创建 map */
  5. countryCapitalMap := map[string]string{"France":"Paris","Italy":"Rome","Japan":"Tokyo","India":"New Delhi"}
  6. fmt.Println("原始 map")
  7. /* 打印 map */
  8. for country := range countryCapitalMap {
  9. fmt.Println("Capital of",country,"is",countryCapitalMap[country])
  10. }
  11. /* 删除元素 */
  12. delete(countryCapitalMap,"France");
  13. fmt.Println("Entry for France is deleted")
  14. fmt.Println("删除元素后 map")
  15. /* 打印 map */
  16. for country := range countryCapitalMap {
  17. fmt.Println("Capital of",country,"is",countryCapitalMap[country])
  18. }
  19. }

Any类型

由于Go语言中任何对象实例都满足空接口interface{},故此interface{}看起来像是可以指向任何对象的Any类型。如下:

  1. var v1 interface{}=1// 将int类型赋值给interface{}
  2. var v2 interface{}="abc"// 将string类型赋值给interface{}
  3. var v3 interface{}=&v2 // 将*interface{}类型赋值给interface{}
  4. var v4 interface{}=struct{ X int}{1}
  5. var v5 interface{}=&struct{ X int}{1}

当一个函数可以接受任意的对象实例时,我们会将其声明为interface{}。最典型的例子是标准库fmt中PrintXXX系列的函数。例如:

  1. func Printf(fmt string, args ...interface{})
  2. func Println(args ...interface{})

类型转换

类型转换用于将一种数据类型的变量转换为另外一种类型的变量。Go 语言类型转换基本格式如下:

type_name(expression)

type_name 为类型,expression 为表达式。

  1. package main
  2. import"fmt"
  3. func main(){
  4. var sum int=17
  5. var count int=5
  6. var mean float32
  7. mean = float32(sum)/float32(count)
  8. fmt.Printf("mean 的值为: %f\n",mean)
  9. }

类型增加方法

在Go语言中,你可以给任意类型(包括内置类型,但指针类型除外)增加方法,例如:

  1. type Integerint
  2. func (a Integer)Less(b Integer)bool{
  3. return a < b
  4. }

在Go语言中没有隐藏的this指针。这句话的含义是:

第一,方法施加的目标(也就是“对象”)显式传递,没有被隐藏起来。
第二,方法施加的目标(也就是“对象”)不需要非得是指针,也不用非得叫this。

在这个例子中,我们定义了一个新类型Integer,它和int没有本质不同,只是它为内置的int类型增加了个新方法:Less。如此,你就可以让整型看起来像个类那样用:
“`go
func main() {
var a Integer = 1
if a.Less(2) {
fmt.Println(a, “Less 2”)
}
}

  1. #变量
  2. Go语言变量名由字母、数字、下划线组成,其中首个字母不能为数字。
  3. 声明变量的一般形式是使用var关键字:
  4. ```go
  5. var identifier type
  6. //指定变量类型,声明后若不赋值,使用默认值。
  7. var v_name v_type
  8. v_name = value
  9. //根据值自行判定变量类型。
  10. var v_name = value
  11. v_name := value
  12. // 省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误。
  13. var a int = 10
  14. var b = 10
  15. c : = 10
  16. //类型相同多个变量, 非全局变量
  17. var x, y int
  18. var ( // 这种因式分解关键字的写法一般用于声明全局变量
  19. a int
  20. b bool
  21. )
  22. var c, d int = 1, 2
  23. var e, f = 123, "hello"
  24. //这种不带声明格式的只能在函数体中出现
  25. //g, h := 123, "hello"
  26. func main(){
  27. g, h := 123, "hello"
  28. println(x, y, a, b, c, d, e, f, g, h)
  29. }

变量作用域

作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。
Go 语言中变量可以在三个地方声明:

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数

值类型和引用类型

多数Go语言中的类型,包括:

基本类型。如byte、int、bool、float32、float64、string等等。
复合类型。如数组(array)、结构体(struct)、指针(pointer)等。

都基于值语义。Go语言中类型的值语义表现得非常彻底。我们这么说是因为数组(array)。如果你学习过C语言,你会知道C语言中的数组(array)比较特别。通过函数传递一个数组的时候基于引用语义,但是在结构体中定义数组变量的时候是值语义(表现在结构体赋值的时候,该数组会被完整地拷贝一份新的副本)。

有4种引用类型:slice,map,channel,interface。

值类型的变量的值存储在栈(stack)中。
当使用等号 = 将一个变量的值赋值给另一个变量时,如:j = i,实际上是在内存中将 i 的值进行了拷贝
可以通过 &i 来获取变量 i 的内存地址,例如:0xf840000040(每次的地址都可能不一样)。
内存地址会根据机器的不同而有所不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同。
更复杂的数据通常会需要使用多个字,这些数据一般使用引用类型保存。

一个引用类型的变量 r1 存储的是 r1 的值所在的内存地址(数字),或内存地址中第一个字所在的位置
这个内存地址为称之为指针,这个指针实际上也被存在另外的某一个字中。
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。
当使用赋值语句 r2 = r1 时,只有引用(地址)被复制。
如果 r1 的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,r2 也会受到影响。

常量

常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的定义格式:

  1. package main
  2. import"fmt"
  3. func main(){
  4. const LENGTH int=10
  5. const WIDTH int=5
  6. var area int
  7. const a, b, c =1,false,"str"//多重赋值
  8. area = LENGTH * WIDTH
  9. fmt.Printf("面积为 : %d", area)
  10. println()
  11. println(a, b, c)
  12. }
  13. //常量还可以用作枚举
  14. const(
  15. Unknown=0
  16. Female=1
  17. Male=2
  18. )
  19. //常量可以用len(), cap(), unsafe.Sizeof()常量计算表达式的值。
  20. const(
  21. a ="abc"
  22. b =

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
go语言入门(8)异常处理发布时间:2022-07-10
下一篇:
速战速决 go - go 面向对象: 包发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap