Golang / 编程开发

Go语言程序结构

温馨提示:本文最后更新于2021-11-11 22:51:44,某些文章具有时效性,若有错误或已失效,请在下方留言或提交工单提交工单
浅时光 · 11月8日 · 2021年 · 本文5563个字,预计阅读14分钟 2297次已读

一、Go语言程序元素


1、标识符

Go语言标识是用于标示变量、函数或任何用户自定义项目的名称(程序实体)。标识符又两种类别,一种是用户定义的标识符,它作为程序实体存在,一般来说同一个代码块中不许程序实体同名,使用不同代码包中的实体需要使用包表示符声明;另一种标识符称为预定义标识符,它们在Go语言源代码中声明。

标识符以字母a~z(大小写均可)或下划线 _ 开头,后面可以是多个字母、下划线和数字。Go语言不允许在标识符中使用标点符号,例如@、$、%等一系列符号。

2、关键字

Go语言作为一门静态编译型语言,它的关键字一共有25个,相比其他编程语言来说显得非常少,因此某种意义上也就更简单了。下面是Go的25个关键字:

  • 包导入与声明:importpackage
  • 程序实体声明与定义:vartypefuncinterfacemapstructchanconst
  • 流程控制:ifcontinueforreturngocasegotoswitchselectelsebreakdefaultdeferfallthroughrange

上面显示的Go的关键字,也称为保留字,这些保留字不能用作常量、变量或任何其他标识符名称。除此之外,还有一个比较特殊的类型叫做空接口,它的字面量是_(下划线)。

3、字面量

字面量就是表示值的一种标记法,但是在Go语言中,字面量的含义要广一些。首先,它用于表示基础数据类型值的各种字面量;其次用于表示用户构造的自定义符合数据类型的类型字面量;最后它还用于表示符合数据类型的值的复合字面量,简单来说,它会被用来构造类型Struct(结构体)、Array(数组)、Slice(切片)和Map(字典)的值。

  • 举例说明:
const b int = 10     //定义了一个常量b,类型为int,b的值为10,而这个10又称为字面量
var str string = "hello world"     //定义了一个变量str,类型为string,值为hello world,而这个hello world就是字面量

4、分隔符

分隔符用于分隔其他元素。程序代码都是通过语句来实现结构化的,但是Go语言不需要以分号 ; 结尾,这些工作由Go语言编译器自动完成。但是,如果将多个语句写在同一行,它们必须使用 ; 分号分隔,实际开发中不鼓励这种写法。

5、运算符

运算符是用于执行运算或逻辑操作的符合。Go语言的运算符如下:

运算符说明
||或,二元逻辑运算符,例如 true || false返回true
&&与,二元逻辑运算符, 例如 true && false返回false
!非, 二元逻辑运算符
==相等判断, 二元逻辑运算符
!=不等判断,二元逻辑运算符
<小于判断,二元逻辑运算符
<=小于等于判断, 二元逻辑运算符
>大于判断,二元逻辑运算符
>=大于等于判断, 二元逻辑运算符
+求和操作,二元算术运算符
求差操作,二元算术运算符
*乘积操作,二元算术运算符
/求商操作,二元算术运算符
|按位或操作, 二元算术运算符
^按位异或操作, 二元算术运算符
%求余操作,二元算术运算符
<<按位左移操作,二元算术运算符
>>按位左移操作,二元算术运算符
&按位与操作,二元算术运算符
&^按位清除操作,二元算术运算符
  • 当一个表达式中有多个运算符时,就会遇到优先级的问题,在Go语言中,一元运算符的优先级高于二元运算符,二元运算符的优先级如下:
运算符优先级
* 、 / 、 % 、 <<、 >>、 &、 &^、最高
+、 -、 |、 ^、较高
==、 !=、 <、 <=、 >、 >=、
&&较低
||最低
  • 如果一个表达式中出现优先级的运算符,那么根据从左到右的顺序依次操作。注意,所有运算符都受括号的影响,括号内先操作,在Go语言中,++--是语句,不是表达式,没有运算优先级之说。
  • Go语言不支持运算符重载

6、注释

Go语言编译器遇到注释会完全忽略。注释是源代码中最重要的组成部分之一,注释的用途非常广泛,例如源代码中写入解释文档

package main

import "fmt"
/*
下面定义了一个main函数,这是程序的入口
这段是块注释
 */
func main() {
	fmt.Println("我爱中国") //这是行注释,打印输出语句 ”我爱中国”
}

二、Go语言的基本概念


1、常量

1.1:数字表示

Go语言的常量可以是十进制、八进制和十六进制常数;

  • 前缀是0x或者0X为十六进制
  • 前缀是0的为八进制
  • 十进制无前缀

整数还可以有一个后缀,它是U和L的组合,分别用于表示unsignedlong。后缀可以是大小写字母,顺序也是任意的。示例如下:

3.14	//十进制,合法
0213	//八进制,合法
0x4b 	//十六进制,合法
0xFeeL  //合法
30u	//无符号整型,合法
30l	//long,  合法
30ul	//无符号 long,  合法
078	//非法 :8 is not an octal digit
032UU	//非法 :cannot repeat a suffix

1.2:转义表示

与其他语言语言,Go语言使用反斜杠表示转义符号,例如换行符(\n)或制表符(\t)

转义序列含义
\\\ 字符
\’‘ 字符
\”” 字符
\?? 字符
\b退格
\f换页
\n换行
\r回车
\t水平制表符
\v垂直制表符
package main

import "fmt"

func main() {
	fmt.Println("hello\tworld!")
	fmt.Println("hello\nworld!")
}


#执行
$ go run Escape.go
hello   world!
hello
world!

1.3:赋值

  • Go语言支持以下赋值运算符:
package main

import "fmt"

func main() {
	a := 20
	c := 200
	c = a
	fmt.Println("赋值操作,把a的值赋值给c,所以c的值为:",c) //现在c的值为20
	c += a
	fmt.Println("相加和赋值运算符,实际为c = c + a,所以c的值为:",c) //在上面c的值为20的基础上在加a的值,所以现在c的值为40
	c -= a
	fmt.Println("相减和赋值运算符,实际为c = c - a,所以c的值为:",c) //在上面c的值为40的基础上减去a的值,所以现在c的值为20
	c *= a
	fmt.Println("相乘和赋值运算符,实际为c = c * a,所以c的值为:",c) //在上面c的值为20的基础上乘以a的值,所以现在c的值为400
	c /= a
	fmt.Println("相除和赋值运算符,实际为c = c / a,所以c的值为:",c) //在上面c的值为400的基础上除以a的值,所以现在c的值为20
	c <<= a
	fmt.Println("左移和赋值运算符,所以c的值为:",c)
	c >>= a
	fmt.Println("右移和赋值运算符,所以c的值为:",c)
	c &= a
	fmt.Println("按位与和赋值运算符,所以c的值为:",c)
	c ^= a
	fmt.Println("按位异和赋值运算符,所以c的值为:",c)
	c |= a
	fmt.Println("按位或和赋值运算符,所以c的值为:",c)
}


#返回结果为:
$ go run assignment.go
赋值操作,把a的值赋值给c,所以c的值为: 20
相加和赋值运算符,实际为c = c + a,所以c的值为: 40
相减和赋值运算符,实际为c = c - a,所以c的值为: 20
相乘和赋值运算符,实际为c = c * a,所以c的值为: 400
相除和赋值运算符,实际为c = c / a,所以c的值为: 20
左移和赋值运算符,所以c的值为: 20971520
右移和赋值运算符,所以c的值为: 20
按位与和赋值运算符,所以c的值为: 20
按位异和赋值运算符,所以c的值为: 0
按位或和赋值运算符,所以c的值为: 20

1.3:枚举

  • 常量还可以用作枚举:
package main

import "fmt"

const (
	a = iota		//返回0
	b		//返回1,隐式使用iota关键字,实际等同于 b = iota + 1
	c		//返回2
	d,e,f = iota,iota,iota	//d==3,e==3,f==3,同一行值相同,此处多个常量则iota也必须对应有几个
	g = iota		//g==4
	h = "h"		//h=="h"
	i		//i==6
	j = iota		//j==7
)

const z = iota  //每个单独定义的const常量中,iota都会重置,此时z == 0
func main() {
	fmt.Println(a,b,c,d,e,f,g,h,i,j)
}
  • 每个const定义的第一个常量被默认设置为0,显式设置了值的常量除外。

2、变量

2.1:变量的声明

变量是Go语言中表示抽象和储存计算结果的一种概念。变量的值通过变量名访问,Go语言的变量名命名规则与常量名一样,都是由字母、数字、下划线组成的,其中名称首个字母不能为数字等。

       变量的声明格式是:var 名称 类型,也就是使用var关键字。Go语言和其他大部分编程语言不同的一个地方,就是它在声明变量时将变量的类型放在变量的名称后面。这样语法从左到右的顺序阅读,更符合人类的语言习惯。

//定义一个变量a为int类型
var a int
//定义一个变量b为bool类型
var b bool
//定义一个变量str为string类型
var str string
//定义两个个变量a、b为int类型
var a, b int

//也可以写到一块
var (
	a ,b int
	c bool
	str string
)

//同一个类型的多个变量可以声明在同一行
var a, b, c int
//多变量可以在同一行进行声明和赋值
var a, b, c int = 1, 2, 3
//多变量可以在同一行进行赋值(下面的方式只能在函数体内赋值)
func variable() {
	a, b = 1, 2
}

2.2:局部变量声明

a := 1    //等同于 var a = 1
  • Go语言编译器会智能推断类型,此处不写 a 变量的类型也是因为Go语言编译器会自动根据值推断出a的类型。
  • Go语言官方推荐使用这种方式定义变量,但是必须注意,它只能被用在函数体内,不可以用于全局变量的声明和赋值,如下示例:
package main

import "fmt"

/*
在全局以这种方式定义变量是错误的,执行会报如下错:
syntax error: non-declaration statement outside function body
 */
//a := 1

//全局定义必须使用var关键字定义
var a = 1

/* 同一个代码块中不能重复定义同一个变量
执行会报错:a redeclared in this block
*/
//var a = 2

func main() {
	b := 1 //在函数体内使用这种简短声明是没有问题的
	a = 100 //把值赋值给a没有语法问题。注意:这里是给a赋值,而不是定义变量,定义变量需要在等号前面加冒号:
	fmt.Println(a)
	a := "hello" //上面全局定义的var 定义a变量属于一个代码块,这里是函数体里面是另外一个代码块,可以再次声明a,改变变量类型
	fmt.Println(a,b,c)  //注意:这里的c调用的是全局变量,并且全局定义的变量不限制位置。结果:hello 1 50

	//不能在调用函数之后定义变量
	//fmt.Println(d)	//先调用后定义,这个是错误的
	//d := 4
}

//全局定义的变量不限定位置,在函数之外即可,在函数之内不可以
var c = 50

/*
输出结果:
100
hello 1 50
 */

使用 := 可以快速创建一个函数内部的变量,它包括初始化声明与赋值两大部分。注意以下几点:

  • 同一个代码块内不能多次声明同一个变量(上面示例中的 var a)
  • 函数内部可以使用全局定义的变量并重新赋值(上面示例中 a = 100)
  • 函数体内属于独立的代码块,可以重新进行声明变量(上面示例中的 a := “hello” ),可以改变变量类型,并且定义只在函数体内部生效
  • 如果在定义变量之前就先调用了该变量,那么会编译错误,返回undefined(上面示例中的变量d)
  • 全局定义不限制位置,但建议统一放在函数代码前面(上面示例中的 var c = 50)

2.3:匿名变量

全局变量自然就是全局可用,局部变量只能在相应的代码块内起作用,除此之外,局部变量还有一个特点就是,定义的必须使用(全局变量允许声明但不使用)。如果定了局部变量,但是却没有在这个代码块中调用这个局部变量,那么编译也会出现错误,例如:

package main

import "fmt"

func main() {
	a := "hello"
	fmt.Println("hello world")
}

//输出结果报错: a declared but not used
  • 所以这里的要求是要被使用,即使是赋值了也会出现报错,这个值必须被使用,例如打印出来,或者赋值给其他变量
  • 在使用强类型语言编程时,经常会出现在调用函数时,该函数返回多个值,其中只有一个值是需要的时候的情况,这个时候就可以使用空标识符来解决这个问题,例如 _=a,这样就不会报错了,这种写法可以忽略一些多返回值的函数的部分返回值。

2.4:init函数

Go语言中,除了可以在全局声明中初始化实体,也可以在init函数中初始化。init函数是一个特殊的函数,它会在包完成初始化后自动执行,执行优先级比main函数高,并且不能手动调用init函数。每一个源文件有且只有一个init函数,初始化过程会根据包的依赖关系按顺序单线程执行。

       可以在开始执行之前通过这个函数来对数据进行检验和修复,保证程序执行时状态。例如:

package main

import (
	"fmt"
	"math"
)
//Pi为圆周率
var Pi float64

func init() {
	Pi = 4* math.Atan(1) //在init函数中计算Pi的值
}

func main() {
	DPi := Pi * Pi
	fmt.Println(Pi, DPi) //结果:3.141592653589793 9.869604401089358
}



本文作者:浅时光
原文链接:https://www.dqzboy.com/9141.html
版权声明:知识共享署名-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)协议进行许可
转载时请以超链接形式标明文章原始出处和作者信息

0 条回应

必须 注册 为本站用户, 登录 后才可以发表评论!

    本站已稳定运行: | 耗时 0.424 秒 | 查询 10 次 | 内存 38.07 MB