go语言--基础语法与使用

Posted zisefeizhu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言--基础语法与使用相关的知识,希望对你有一定的参考价值。

从“Hello World”开始

代码

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main()  
 8     /*
 9         这是学习Goglang语言的最开始的地方
10      */
11     fmt.Println("Hello World!")
12     //输出Hello World!
13 

解释

第一行:

  • package是最基本的分发单位和工程管理中依赖关系的体现

  • 每个Go语言源代码文件开头都必须要有一个package声明,表示源代码文件所属包

  • 要生成Go语言可执行程序,必须要有名为mainpackage包,且在该包下必须有且只有一个main函数

  • 同一个路径下只能存在一个package,一个package可以由多个源代码文件组成

  • 一个目录就是一个包,该目录下的所有文件必须属于同一个包。

第三 ~ 五行:
  • import语句的唯一作用就是导入源码文件所依赖的包,而且导入的包必须在源码文件里用到,否则会报错(在VS Code里如果输入一个没有导入的包函数,VS Code会自动导入)
  • import这个命令用来导入包文件,fmt是Go语言的标准库,他其实是去GOROOT下去加载该模块,当然Go的import还支持如下两种方式来加载自己写的模块:     
  1. 相对路径  import "./model"  //当前文件同一目录的model目录,但是不建议这种方式import
  2.  绝对路径  import "shorturl/model"  //加载GOPATH技术图片c技术图片orturl/model模块 
  • import的写法有两种格式,我个人更倾向于第二种
第一种: 
    import "fmt"
第二种: import (       "fmt"     )
  • 如果一个main导入其他的包,包会被顺序导入
  • 如果导入的包(pkg1)依赖其他的包(包pkg2),会首先导入pkg2,然后初始化pkg2中的常量与变量,如果pkg2中有init函数,会自动执行init
  • 所有包导入完成后才会对main的常量和变量进行初始化,然后执行main中的init函数(如果有的话),最后执行main函数
  • 如果一个包被导入多次实际上只会导入一次
第七行:
  • func:Go的函数声明关键字,声明一个函数
  • main()其实就是一个函数,而且是一个比较特殊的函数
  • 每个go程序都是从名为main的package包的main()函数开始执行
  • main()函数是无参数,无返回值的。

第八  ~ 十,十二行:

  •  /*   */   多行注释
  •  //        单行注释

第十一行:

  • fmt.Println是打印到终端字符串

结果

技术图片

再来一个例子

package main

import 
  "net/http"
func main( ) http.Handle("/",http.FileServer(http.Dir("."))) http.ListenAndServe(":8080",nil) 第1行,标记当前文件为main包,main包也是Go程序的入口包 第3行,导入net/http包,这个包的作用是HTTP的基础封装和访问 第7行,程序执行的入口函数main() 第8行,使用http.FileServer 文件服务器将当前目录作为根目录(“/” )的处理器,访问根目录,就会进入当前目录。 第10行,默认的HTTP服务侦听在本机8080端口

在浏览器里输入 http://127.0.0. l :8080 可浏览文件,这些文件正是当前目录在 HTTP服务器上的映射目录。

技术图片

Go语言常见库

Go语言标准库包名功  能
bufio 带缓冲的 I/O 操作
bytes 实现字节操作
container 封装堆、列表和环形列表等容器
crypto 加密算法
database 数据库驱动和接口
debug 各种调试文件格式访问及调试功能
encoding 常见算法如 JSON、XML、Base64 等
flag 命令行解析
fmt 格式化操作
go Go 语言的词法、语法树、类型等。可通过这个包进行代码信息提取和修改
html HTML 转义及模板系统
image 常见图形格式的访问及生成
io 实现 I/O 原始访问接口及访问封装
math 数学库
net 网络库,支持 Socket、HTTP、邮件、RPC、SMTP 等
os 操作系统平台不依赖平台操作封装
path 兼容各操作系统的路径操作实用函数
plugin Go 1.7 加入的插件系统。支持将代码编译为插件,按需加载
reflect 语言反射支持。可以动态获得代码中的类型信息,获取和修改变量的值
regexp 正则表达式封装
runtime 运行时接口
sort 排序接口
strings 字符串转换、解析及实用函数
time 时间接口
text 文本模板及 Token 词法器

 库的帮助文档:

  • go doc  库/包
  • https://golang.google.cn/

变量

  • 变量的功能是存储用户的数据 不同的逻辑有不同的对象类型,也就有不同的变量类型
  • 常见变量的数据类型有:整型、浮点型、布尔型、结构体等。
  • Go语言作为C语言家族的新派代表,在C语言的定义方法和类型上做了优化和调整,更加灵活易学。
  • Go 语言的每一个变量都拥有自己的类型,必须经过声明才能开始用。

 

声明变量

先通过一段代码了解变量声明的基本样式

 

1 var a int
2 var b string
3 var c [] float32
4 var d func() bool
5 var e struct 
6         x int
7 

代码说明

  • 第1行,声明一个整型类型的变量,可以保存整数数值。
  • 第2行,声明一个字符串类型的变量
  • 第3行,声明一个32位浮点切片类型的变量,浮点切片表示由多个浮点类型组成的数据结构。
  • 第4行,声明一个返回值为布尔类型的函数变量,这种形式一般用于回调函数,即将函数以变量的形式保存下来,在需要的时候重新调用这个函数。
  • 第5行,声明一个结构体类型的变量,这个结构体拥有一个整型的x字段。

上面代码的共性是,以 var 关键字开头,要声明 的变量 名放在中间,而将其类型放在后面
Go语言的变量声明的标准格式为
  var 变量名 变量类型
变量声明 关键字 var 开头,后置变量类型,行尾无须分号
批量格式
  这是一种为懒人提供的定义变量的方法:

 

 1 var (
 2     a int
 3     b string
 4     c [] float32
 5     d func() bool
 6     e struct 
 7         x int
 8     
 9 )
10 使用关键 var 和括 ,可以将 组变量定义放在一起。

初始化变量
Go 语言在声明变量时,自动对变量对应的内存区域进行初始化操作 。每个变量会初始化
其类型的默认值,例如:

  • 整型和浮点型变量的默认值为0
  • 字符串变量的默认值为空字符串。
  • 布尔型变量默认为 bool
  • 切片、函数 、指针变量的默认为 nil

当然,依然可以在变量声明时赋予变量一个初始值
标准格式
  var 变量名类型=表达式
例子:游戏中,玩家的血量初始值为 100 。可以这样写:
  var hp int = 100
这句代码中,hp为变量名,类型为int, hp 的初始值为 100

 

编译器推导类型的格式
在标准格式的基础上,将 int 省略后,编译器会尝试根据等号右边的表达式推导 hp变量的类型。
  var hp = 100
等号右边的部分在编译原理里被称做“右值”。
下面是编译器根据右值推导变量类型完成初始化的例子

 

1 var attack = 40
2 var defence = 20
3 var damageRate float32 = 0.17
4 var damage= float32(attack-defence) * damageRate
5 fmt.Println(damage)

 

代码说明:

  • 第1和2行,右值为整型, attack和defence变量的类型为 int
  • 第3行,表达式的右值中使用了 0.17 . Go 语言和C语言一样,编译器会尽量提高精确度,以避免计算中的精度损失。默认情况下,如果不指定 damageRate 变量的类型, 语言编译器会将 damageRate类型推导为 float64 。由于这个例子中不需要 float64 的精度,所以强制指定类型为 float32
  • 第4行,将 attack defence 相减后的数值结果依然为整型,使用 float32 ()将结果转换为 float32 类型,再与 float32 类型的 damageRate 相乘后, damage 类型也是 float32类型。
  • 第5行,输出 damage 的值

 

短变量声明并初始化
例子:游戏中,玩家的血量初始值为 100 。还可以这样写
hp := 100
这是 Go 语言的推导声明写法,编译器会自动根据右值类型推断出左值的对应类型。
由于使用了“:=”,而不是赋值的“=” 因此推导声明写法的左值变量必须是没有定义过的变量。若定义过,将会发生编译错误。
例如:如果hp已经被声明过,但依然使用“:=”时编译器会报错, 代码如下:
//声明 hp 变量
var hp int
//再次声明并赋值
hp : = 10
编译报错如下:
no new variables on left side of :=
提示 在“:=” 的左边没有新变量出现,意思就是“:=”的左边变量已经被声明了。

 

短变量声明的形式在开发中 的例子较多, 比如:
conn, err :=net.Dial("tcp","127.0.0.1:8080")
net.Dial 提供按指定协议和地址发起网络连接,这个函数有两个返回值,一个是连接对象,一个是err对象。如果是标准格式将会变成:
var conn net.Conn
var err error
conn , err = net Dial("tcp","127.0.0.1:8080")
因此,短变量声明并初始化的格式在开发中使用比较普遍。
注意:在多个短变量声明和赋值中,至少有一个新声明的变量出现在左值中,即使其他变量名可能是重复声明的 ,编译器也不会报错,代码如下:
conn, err := net.Dial (”tcp”,”127.0 . 0 . 1 : 8080 ”)
conn2, err := net.Dial("tcp","127.0.0.1:8080")
上面的代码片段,编译器不会报err重复定义。

 

多个变量同时赋值
编程最简单的算法之一 ,莫过于变量交换。交换变量的常见算法需要一个中间变量进行变量的临时保存。用传统方法编写变量交换代码如下:
var a int = 100
var b int = 200
var t int
t = a
a = b
b = t
fmt.Println(a , b)

到了Go语言时,内存不再是紧缺资源,而且写法可以更简单。使用 Go 的“多重赋值”特性,可以轻松完成变量交换的任务:

var a int = 100
var b int = 200
b,a = a,b
fmt.Println(a,b)
多重赋值时,变量的左值和右值按从左到右的顺序赋值。
多重赋值在 Go 语言的错误处理和函数返回值中会大量地使用。

例如,使用 Go语言进行排序时就需要使用交换,代码如下:
type IntSlice []int
func (p IntSlice) Len () int return len (p )
func (p IntSlice) Less (i , j int) bool return p[i] < p [j]
func (p IntSlice ) Swap (i , j int) p[i], p[j] = p[j] , p[i]

代码说明:
第1行,将[]int声明为 IntSlice 类型。
第2行,为这个类型编写一个Len方法,提供切片的长度。
第3行,根据提供的i,j元素索引,获取元素后进行比较,返回比较结果。
第4行,根据提供的i,j元素索引,交换两个元素的值。

 

匿名变量一一没有名字的变量
在使用多重赋值时,如果不需要在左值中接收变量 可以使用匿名变量。
在编码过程中,可能会遇到没有名称的变量、类型或方法。虽然这不是必须的,但有时候这样做可以极大地增强代码的灵活性,这些变量被统称为匿名变量。
匿名变量的特点是一个下画线“_”,“_”本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个这个标识符作为变量对其它变量的进行赋值或运算。使用匿名变量时,只需要在变量声明的地方使用下画线替换即可

例如:
func GetData() (int, int)
return 100, 200

a, _ := GetData()
_, b := GetData()
fmt.Println(a, b)

代码解释
GetData() 是一个函数,拥有两个整型返回值。每次调用将会返回 100 和 200 两个数值。

代码说明如下:
第 4 行只需要获取第一个返回值,所以将第二个返回值的变量设为下画线。
第 5 行将第一个返回值的变量设为匿名。
匿名变量不占用命名空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用。

数据类型

Go 语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型 字符串外,还有切片、结构体 函数、 map 通道( channel )等。
切片类型有着指针的便利性,但比指针更为安全 很多高级语言都配有切片进行安全和高效率的内存操作。

整型
整型分为以下两个大类
按长度分为:int8 int16 int32 int64
还有对应的无符号整型: uint8 uint16 uint32 uint64
其中, uint8 就是我们熟知的 byte 型, intl6 对应C语言中的 short 型, int64 对应C语言中的 long 型。

1. 自动匹配平台的int uint
Go 语言也有自动皮配特定平台整型长度的类型--int和 uint。可以跨平台的编程语言可以运行在多种平台上。平台的字节长度是有差异的。 64位平台现今已经较为普及,但8位、 16 位、 32 系统依旧存在。 16 位平台上依然可使用 64 位的变量, 但运行性能和内存性能上较差。 同理,在 64 位平台上大量使用8位、16 位等与平台位数不等长的变量时,编译器也是尽量将内存对齐以获得最好的性能。不能正确匹配平台字节长度的程序就类似于用轿车运一头牛和用一辆卡车运送一头牛的情形一样。在使用 int和 uint 类型时,不能假定它是 32 位或 64 整型,而是考虑 int和 uint可能在不同平台上 差异。
2. 哪些情况下使用 int 和uint
逻辑对整型范围没有特殊需求。 例如,对象的长度使用内 len ()函 返回 ,这个长度可以根据不同平台的长度进行变化 。实际使用中 切片 map 的元素数量等都可以用int 来表示。反之,在二进制传输、读写文件的结构描述时 为了保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用 int uint
3. 大多数情况下,我们只需要 int 一种整型即可,它可以用于循环计数器、数组、切片索引,以及任何通用目的的整型运算符,通常 int 类型的处理速度也是最快的。
4. 还有一种无符号的整数类型 uintptr,没有指定具体的 bit 大小但是足以容纳指针。uintptr 类型只有在底层编程时才需要,特别是 Go语言和 C语言函数库或操作系统接口相交互的地方

 

浮点数
Go语言支持两种精度的浮点数,float32 和 float64。它们的算术规范由 IEEE754 浮点数国际标准定义,该浮点数规范被所有现代的 CPU 支持。
这些浮点数类型的取值范围可以从很微小到很巨大。浮点数的范围极限值可以在 math 包找到。
常量 math.MaxFloat32 表示 float32 能表示的最大数值,大约是 3.4e38;
对应的 math.MaxFloat64 常量大约是 1.8e308。它们分别能表示的最小值近似为 1.4e-45 和 4.9e-324。
一个 float32 类型的浮点数可以提供大约 6 个十进制数的精度,而 float64 则可以提供约 15 个十进制数的精度;通常应该优先使用 float64 类型,因为 float32 类型的累计计算误差很容易扩散,并且 float32 能精确表示的正整数并不是很大。
提示:因为 float32 的有效 bit 位只有 23 个,其它的 bit 位用于指数和符号;当整数大于 23bit 能表达的范围时,float32 的表示将出现误差

例子代码:

 1 package main
 2 
 3 import (
 4 "fmt"
 5 "math"
 6 )
 7 
 8 func main() 
 9 
10 fmt.Printf("%f\\n",math.Pi)
11 
12 fmt.Printf("% .2f\\n",math.Pi)
13 

复数
Go语言拥有以下两种复数类型:

  • complex64 (32 位实数和虚数)
  • complex128 (64 位实数和虚数)

内置的 complex 函数用于构建复数,内建的 real 和 imag 函数分别返回复数的实部和虚部:
var x complex128 = complex(1, 2) // 1+2i
var y complex128 = complex(3, 4) // 3+4i
fmt.Println(x*y) // "(-5+10i)"
fmt.Println(real(x*y)) // "-5"
fmt.Println(imag(x*y)) // "10"
复数使用 re+imI 来表示,其中 re 代表实数部分,im 代表虚数部分,I 代表根号负 1。如果一个浮点数面值或一个十进制整数面值后面跟着一个 i,例如 3.141592i 或 2i,它将构成一个复数的虚部,复数的实部是0:
fmt.Println(1i * 1i) // "(-1+0i)", i^2 = -1
如果 re 和 im 的类型均为 float32,那么类型为 complex64 的复数 c 可以通过以下方式来获得:
c = complex(re, im)
函数 real(c) 和 imag(c) 可以分别获得相应的实数和虚数部分。

在使用格式化说明符时,可以使用 %v 来表示复数,但当你希望只表示其中的一个部分的时候需要使用 %f。

复数支持和其它数字类型一样的运算。当你使用等号 == 或者不等号 != 对复数进行比较运算时,注意对精确度的把握。cmath 包中包含了一些操作复数的公共方法。如果你对内存的要求不是特别高,最好使用 complex128 作为计算类型,因为相关函数都使用这个类型的参数。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于go语言--基础语法与使用的主要内容,如果未能解决你的问题,请参考以下文章

Go Web编程实战----Go语言的基础语法

Go Web编程实战----Go语言的基础语法

Go Web编程实战----Go语言的基础语法

每天一点Go语言——Go语言语法基础及基本数据类型

go语言基础语法-for循环语句

go语言基础语法-for循环语句