目录

Go - 快速指南

Go - Overview

Go是一种通用语言,专为系统编程而设计。 它最初是由Robert Griesemer,Rob Pike和Ken Thompson于2007年在谷歌开发的。 它强大且静态地输入,为垃圾收集提供内置支持,并支持并发编程。

程序是使用包构建的,用于有效管理依赖关系。 Go编程实现使用传统的编译和链接模型来生成可执行的二进制文件。 Go编程语言于2009年11月宣布,并在一些Google的生产系统中使用。

Go编程的特点

Go编程最重要的功能如下 -

  • 支持环境采用类似于动态语言的模式。 例如,类型推断(x:= 0是int类型的变量x的有效声明)

  • 编译时间很快。

  • 内置并发支持:轻量级进程(通过go例程),通道,select语句。

  • Go程序简单,简洁,安全。

  • 支持接口和类型嵌入。

  • 生成静态链接的本机二进制文件,没有外部依赖项。

故意排除的功能

为了使语言简洁明了,Go中省略了其他类似语言中常用的以下功能 -

  • 支持类型继承

  • 支持方法或运算符重载

  • 支持包之间的循环依赖

  • 支持指针运算

  • 支持断言

  • 支持通用编程

Go Programs

Go程序的长度可以从3行到数百万行不等,并且应该写入一个或多个扩展名为“.go”的文本文件。 例如,hello.go。

您可以使用“vi”,“vim”或任何其他文本编辑器将Go程序写入文件。

Go - Environment Setup

本地环境设置 (Local Environment Setup)

如果您仍然愿意为Go编程语言设置环境,则需要在计算机上使用以下两个软件 -

  • 文本编辑器
  • Go编译器

文本编辑器 (Text Editor)

您将需要一个文本编辑器来键入您的程序。 文本编辑器的示例包括Windows Notepad,OS Edit命令,Brief,Epsilon,EMACS和vim或vi。

文本编辑器的名称和版本可能因不同的操作系统而异。 例如,在Windows上使用记事本,在Windows以及Linux或UNIX上使用vim或vi。

使用文本编辑器创建的文件称为source files 。 它们包含程序源代码。 Go程序的源文件通常以扩展名".go"命名。

在开始编程之前,请确保您已准备好文本编辑器,并且您有足够的经验来编写计算机程序,将其保存在文件中,编译并最终执行。

Go编译器

源文件中编写的源代码是程序的可读源代码。 它需要编译并转换为机器语言,以便您的CPU可以按照给出的指令实际执行程序。 Go编程语言编译器将源代码编译为其最终的可执行程序。

Go发布是FreeBSD(版本8及更高版本),Linux,Mac OS X(Snow Leopard及以上版本)以及具有32位(386)和64位(amd64)x86处理器架构的Windows操作系统的二进制安装。

以下部分说明如何在各种OS上安装Go二进制分发。

下载Go Archive

Go Downloads下载最新版本的Go可安装存档文件。 本教程使用以下版本: go1.4.windows-amd64.msi

它被复制到C:\> go文件夹中。

OS 存档名称
Windowsgo1.4.windows-amd64.msi
Linuxgo1.4.linux-amd64.tar.gz
Macgo1.4.darwin-amd64-osx10.8.pkg
FreeBSDgo1.4.freebsd-amd64.tar.gz

在UNIX/Linux/Mac OS X和FreeBSD上安装

将下载存档解压缩到/ usr/local文件夹,在/ usr/local/go中创建Go树。 例如 -

tar -C/usr/local -xzf go1.4.linux-amd64.tar.gz

将/ usr/local/go/bin添加到PATH环境变量。

OS output
Linux export PATH = $ PATH:/ usr/local/go/bin
Mac export PATH = $ PATH:/ usr/local/go/bin
FreeBSD export PATH = $ PATH:/ usr/local/go/bin

Installation on Windows

使用MSI文件并按照提示安装Go工具。 默认情况下,安装程序使用c:\​​ Go中的Go分发。 安装程序应在Window的PATH环境变量中设置c:\Go\bin目录。 重新启动任何打开命令提示更改才能生效。

验证安装

C:\》Go_WorkSpace创建一个名为test.go的go文件。

File: test.go

package main
import "fmt"
func main() {
   fmt.Println("Hello, World!")
}

现在运行test.go查看结果 -

C:\Go_WorkSpace>go run test.go

输出 (Output)

Hello, World!

Go - Program Structure

在我们研究Go编程语言的基本构建块之前,让我们先讨论Go程序的最小结构,以便我们可以在后续章节中作为参考。

Hello,World!的例子

Go程序基本上由以下部分组成 -

  • 包装声明
  • 导入包
  • Functions
  • Variables
  • 声明和表达
  • Comments

让我们看一下打印“Hello World”字样的简单代码 -

package main
import "fmt"
func main() {
   /* This is my first sample program. */
   fmt.Println("Hello, World!")
}

让我们看一下上述计划的各个部分 -

  • 程序包main的第一行定义了该程序所在的包名。 这是一个强制性声明,因为Go程序在包中运行。 主程序包是运行程序的起点。 每个包都有一个与之关联的路径和名称。

  • 下一行导入“fmt”是一个预处理器命令,它告诉Go编译器包含位于包fmt中的文件。

  • 下一行func main()是程序执行开始的主要功能。

  • 下一行/*...*/被编译器忽略,它可以在程序中添加注释。 注释也使用//表示类似于Java或C ++注释。

  • 下一行fmt.Println(...)是Go中另一个可用的函数,它会导致消息“Hello,World!” 显示在屏幕上。 这里fmt包已经导出了Println方法,用于在屏幕上显示消息。

  • 注意Println方法的大写P. 在Go语言中,如果以大写字母开头,则会导出名称。 导出意味着相应包的导入者可以访问函数或变量/常量。

执行Go程序

让我们讨论如何将源代码保存在文件中,编译它,最后执行程序。 请按照以下步骤进行操作 -

  • 打开文本编辑器并添加上述代码。

  • 将文件另存为hello.go

  • 打开命令提示符。

  • 转到保存文件的目录。

  • 输入go run hello.go并按Enter键运行代码。

  • 如果您的代码中没有错误,那么您将看到"Hello World!" 印在屏幕上。

$ go run hello.go
Hello, World!

确保Go编译器在您的路径中,并且您在包含源文件hello.go的目录中运行它。

Go - Basic Syntax

我们在前一章讨论了Go程序的基本结构。 现在,很容易理解Go编程语言的其他基本构建块。

Go中的代币

Go程序由各种令牌组成。 标记是关键字,标识符,常量,字符串文字或符号。 例如,以下Go语句由六个标记组成 -

fmt.Println("Hello, World!")

个人代币是 -

fmt
.
Println
(
   "Hello, World!"
)

线分隔符

在Go程序中,行分隔符键是语句终止符。 也就是说,单个语句不需要像C中的“;”那样的特殊分隔符.Go编译器在内部放置“;”作为语句终止符以指示一个逻辑实体的结束。

例如,看看以下声明 -

fmt.Println("Hello, World!")
fmt.Println("I am in Go Programming World!")

注释 (Comments)

注释就像在Go程序中帮助文本一样,编译器会忽略它们。 它们以/ *开头并以字符* /结尾,如下所示 -

/* my first program in Go */

您不能在注释中添加注释,也不会在字符串或字符文字中出现。

标识符 (Identifiers)

Go标识符是用于标识变量,函数或任何其他用户定义项的名称。 标识符以字母A到Z或a到z或下划线_开头,后跟零个或多个字母,下划线和数字(0到9)。

identifier = letter {letter | unicode_digit}。

Go不允许标识符中的标点符号,如@,$和%。 Go是一种case-sensitive编程语言。 因此, Manpowermanpower是Go中的两个不同的标识符。 以下是可接受标识符的一些示例 -

mahesh      kumar   abc   move_name   a_123
myname50   _temp    j      a23b9      retVal

关键字 (Keywords)

以下列表显示了Go中的保留字。 这些保留字不能用作常量或变量或任何其他标识符名称。

breakdefaultfuncinterfaceselect
casedeferGomapStruct
chanelseGotopackageSwitch
constfallthroughifrangeType
continueforimportreturnVar

Go中的空白

Whitespace是Go中用于描述空格,制表符,换行符和注释的术语。 只包含空格(可能带有注释)的行称为空行,Go编译器完全忽略它。

空格将语句的一部分与另一部分分开,并使编译器能够识别语句中的一个元素(如int)的结束位置以及下一个元素的开始位置。 因此,在以下声明中 -

var age int;

在int和age之间必须至少有一个空格字符(通常是空格),以便编译器能够区分它们。 另一方面,在以下声明中 -

fruit = apples + oranges;   // get the total fruit

水果和=之间,或=和苹果之间不需要空白字符,但如果您希望出于可读性目的,可以自由添加一些空白字符。

Go - Data Types

在Go编程语言中,数据类型是指用于声明不同类型的变量或函数的扩展系统。 变量的类型决定了它在存储中占用的空间大小以及如何解释存储的位模式。

Go中的类型可分为以下几类 -

Sr.No. 类型和描述
1

Boolean types

它们是布尔类型,由两个预定义常量组成:(a)true(b)false

2

Numeric types

它们又是算术类型,它们代表a)整数类型或b)整个程序中的浮点值。

3

String types

字符串类型表示字符串值的集合。 它的值是一个字节序列。 字符串是一旦创建的不可变类型,就不可能更改字符串的内容。 预先声明的字符串类型是字符串。

4

Derived types

它们包括(a)指针类型,(b)数组类型,(c)结构类型,(d)联合类型和(e)函数类型f)切片类型g)接口类型h)地图类型i)通道类型

数组类型和结构类型统称为aggregate types 。 函数的类型指定具有相同参数和结果类型的所有函数的集合。 我们将在下一节讨论基本类型,而其他类型将在后面的章节中介绍。

整数类型 (Integer Types)

预定义的与体系结构无关的整数类型是 -

Sr.No. 类型和描述
1

uint8

无符号8位整数(0到255)

2

uint16

无符号16位整数(0到65535)

3

uint32

无符号32位整数(0到4294967295)

4

uint64

无符号64位整数(0到18446744073709551615)

5

int8

有符号8位整数(-128到127)

6

int16

有符号16位整数(-32768到32767)

7

int32

有符号32位整数(-2147483648到2147483647)

8

int64

有符号64位整数(-9223372036854775808至9223372036854775807)

浮动类型

预定义的独立于体系结构的浮点类型是 -

Sr.No. 类型和描述
1

float32

IEEE-754 32位浮点数

2

float64

IEEE-754 64位浮点数

3

complex64

具有float32实部和虚部的复数

4

complex128

带有float64实部和虚部的复数

n位整数的值是n位,并使用二进制补码算术运算来表示。

其他数字类型

还有一组具有特定于实现的大小的数字类型 -

Sr.No. 类型和描述
1

byte

与uint8相同

2

rune

与int32相同

3

uint

32或64位

4

int

与uint相同的大小

5

uintptr

无符号整数,用于存储指针值的未解释位

Go - Variables

变量只不过是程序可以操作的存储区域的名称。 Go中的每个变量都有一个特定的类型,它决定了变量内存的大小和布局,可以存储在该内存中的值的范围,以及可以应用于变量的操作集。

变量的名称可以由字母,数字和下划线字符组成。 它必须以字母或下划线开头。 大写和小写字母是不同的,因为Go区分大小写。 基于前一章中解释的基本类型,将有以下基本变量类型 -

Sr.No 类型和描述
1

byte

通常是一个八位字节(一个字节)。 这是一种字节类型。

2

int

机器最自然的整数大小。

3

float32

单精度浮点值。

Go编程语言还允许定义各种其他类型的变量,如枚举,指针,数组,结构和联合,我们将在后续章节中讨论。 在本章中,我们将仅关注基本变量类型。

Go中的变量定义

变量定义告诉编译器为变量创建的存储位置和数量。 变量定义指定数据类型,并包含该类型的一个或多个变量的列表,如下所示 -

var variable_list optional_data_type;

这里, optional_data_type是一个有效的Go数据类型,包括byte,int,float32,complex64,boolean或任何用户定义的对象等, variable_list可以包含一个或多个用逗号分隔的标识符名称。 这里显示了一些有效的声明 -

var  i, j, k int;
var  c, ch byte;
var  f, salary float32;
d =  42;

语句“var i, j, k;”声明并定义变量i,j和k; 它指示编译器创建int类型的名为i,j和k的变量。

变量可以在其声明中初始化(分配初始值)。 变量的类型由编译器根据传递给它的值自动判断。 初始化程序包含一个等号,后跟一个常量表达式,如下所示 -

variable_name = value;

例如,

d = 3, f = 5;    // declaration of d and f. Here d and f are int 

对于没有初始化程序的定义:具有静态存储持续时间的变量用nil隐式初始化(​​所有字节的值都为0); 所有其他变量的初始值为其数据类型的零值。

Go中的静态类型声明

静态类型变量声明为编译器提供了保证,即存在一个具有给定类型和名称的变量,以便编译器可以继续进行进一步编译,而无需变量的完整细节。 变量声明仅在编译时有意义,编译器在链接程序时需要实际的变量声明。

例子 (Example)

尝试以下示例,其中变量已使用类型声明并在main函数内初始化 -

package main
import "fmt"
func main() {
   var x float64
   x = 20.0
   fmt.Println(x)
   fmt.Printf("x is of type %T\n", x)
}

编译并执行上述代码时,会产生以下结果 -

20
x is of type float64

Go中的动态类型声明/类型推断

动态类型变量声明要求编译器根据传递给它的值来解释变量的类型。 编译器不需要变量将静态类型作为必要的要求。

例子 (Example)

尝试以下示例,其中声明的变量没有任何类型。 注意,在类型推断的情况下,我们使用:=运算符初始化变量y ,而使用=运算符初始化x

package main
import "fmt"
func main() {
   var x float64 = 20.0
   y := 42 
   fmt.Println(x)
   fmt.Println(y)
   fmt.Printf("x is of type %T\n", x)
   fmt.Printf("y is of type %T\n", y)	
}

编译并执行上述代码时,会产生以下结果 -

20
42
x is of type float64
y is of type int

Go中的混合变量声明

可以使用类型推断一次声明不同类型的变量。

例子 (Example)

package main
import "fmt"
func main() {
   var a, b, c = 3, 4, "foo"  
   fmt.Println(a)
   fmt.Println(b)
   fmt.Println(c)
   fmt.Printf("a is of type %T\n", a)
   fmt.Printf("b is of type %T\n", b)
   fmt.Printf("c is of type %T\n", c)
}

编译并执行上述代码时,会产生以下结果 -

3
4
foo
a is of type int
b is of type int
c is of type string

Go中的左值和右值

Go中有两种表达方式 -

  • lvalue - 引用内存位置的表达式称为“左值”表达式。 左值可以显示为赋值的左侧或右侧。

  • rvalue - 术语rvalue是指存储在内存中某个地址的数据值。 rvalue是一个不能赋值给它的表达式,这意味着rvalue可能出现在赋值的右边但不是左边。

变量是左值,因此可能出现在赋值的左侧。 数字文字是右值,因此可能无法分配,也不能出现在左侧。

以下声明有效 -

x = 20.0

以下声明无效。 它会生成编译时错误 -

10 = 20

Go - Constants

常量是指程序在执行期间不会改变的固定值。 这些固定值也称为literals

常量可以是任何基本数据类型,如an integer constant, a floating constant, a character constant, or a string literal 。 还有枚举常量。

常量被视为常规变量,除了它们的值在定义后无法修改。

整型常量 (Integer Literals)

整数文字可以是十进制,八进制或十六进制常量。 前缀指定基数或基数:十六进制为0x或0X,八进制为0,十进制为空。

整数文字也可以有一个后缀,它是U和L的组合,分别对于unsigned和long。 后缀可以是大写或小写,可以按任何顺序排列。

以下是整数文字的一些示例 -

212         /* Legal */
215u        /* Legal */
0xFeeL      /* Legal */
078         /* Illegal: 8 is not an octal digit */
032UU       /* Illegal: cannot repeat a suffix */

以下是各种类型的整数文字的其他示例 -

85         /* decimal */
0213       /* octal */
0x4b       /* hexadecimal */
30         /* int */
30u        /* unsigned int */
30l        /* long */
30ul       /* unsigned long */

浮点型常量 (Floating-point Literals)

浮点文字有一个整数部分,一个小数点,一个小数部分和一个指数部分。 您可以以十进制形式或指数形式表示浮点文字。

在使用小数形式表示时,必须包括小数点,指数或两者,并且在使用指数形式表示时,必须包括整数部分,小数部分或两者。 带符号的指数由e或E引入。

以下是浮点文字的一些示例 -

3.14159       /* Legal */
314159E-5L    /* Legal */
510E          /* Illegal: incomplete exponent */
210f          /* Illegal: no decimal or exponent */
.e55          /* Illegal: missing integer or fraction */

逃脱序列

当某些字符前面有反斜杠时,它们在Go中具有特殊含义。 这些被称为转义序列代码,用于表示换行符(\ n),制表符(\ t),退格键等。这里,您有一些此类转义序列代码的列表 -

逃脱序列 含义
\\ \字符
\' ' character(字符)
\" " character(字符)
\? ? 字符
\aAlert or bell
\bBackspace
\fForm feed
\nNewline
\rCarriage return
\t 水平标签
\v 垂直标签
\ooo 八进制数字为一到三位数
\xhh。 。 。 十六进制数字的一个或多个数字

以下示例显示如何在程序中使用\t -

package main
import "fmt"
func main() {
   fmt.Printf("Hello\tWorld!")
}

编译并执行上述代码时,会产生以下结果 -

Hello World!

Go中的字符串文字

字符串文字或常量用双引号“”括起来。 字符串包含与字符文字类似的字符:普通字符,转义序列和通用字符。

您可以使用字符串文字将长行分成多行,并使用空格分隔它们。

以下是字符串文字的一些示例。 所有三种形式都是相同的字符串。

"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"

const关键字

您可以使用const前缀来声明具有特定类型的常量,如下所示 -

const variable type = value;

以下示例显示如何使用const关键字 -

package main
import "fmt"
func main() {
   const LENGTH int = 10
   const WIDTH int = 5   
   var area int
   area = LENGTH * WIDTH
   fmt.Printf("value of area : %d", area)   
}

编译并执行上述代码时,会产生以下结果 -

value of area : 50

请注意,在CAPITALS中定义常量是一种很好的编程习惯。

Go - Operators

运算符是一个符号,告诉编译器执行特定的数学或逻辑操作。 Go语言内置运算符丰富,并提供以下类型的运算符 -

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 按位运算符
  • 分配运算符
  • 其它运算符

本教程逐个解释算术,关系,逻辑,按位,赋值和其他运算符。

算术运算符 (Arithmetic Operators)

下表显示了Go语言支持的所有算术运算符。 假设变量A保持10,变量B保持20然后 -

显示示例

操作者 描述
+ 添加两个操作数 A + B给出30
- 从第一个减去第二个操作数 A - B给-10
* 将两个操作数相乘 A * B给出200
/ 用分母除以分子。 B/A给出2
% 模数算子; 在整数除法后给出余数。 B%A给出0
++ 增量运算符。 它将整数值增加1。 A ++给出11
-- 递减运算符。 它将整数值减1。 A-- gives 9

关系运算符 (Relational Operators)

下表列出了Go语言支持的所有关系运算符。 假设变量A保持10,变量B保持20,则 -

显示示例

操作者 描述
== 它检查两个操作数的值是否相等; 如果是,则条件成立。 (A == B)不是真的。
!= 它检查两个操作数的值是否相等; 如果值不相等,则条件成立。 (A!= B)是真的。
> 它检查左操作数的值是否大于右操作数的值; 如果是,则条件成立。 (A> B)不是真的。
< 它检查左操作数的值是否小于右操作数的值; 如果是,则条件成立。 (A < B) 为真
>= 它检查左操作数的值是否大于或等于右操作数的值; 如果是,则条件成立。 (A> = B)不是真的。
<= 它检查左操作数的值是否小于或等于右操作数的值; 如果是,则条件成立。 (A <= B)是真的。

逻辑运算符 (Logical Operators)

下表列出了Go语言支持的所有逻辑运算符。 假设变量A保持1而变量B保持0,则 -

显示示例

操作者 描述
&& 称为逻辑AND运算符。 如果两个操作数都不为零,则条件成立。 (A && B)是假的。
|| 称为逻辑OR运算符。 如果两个操作数中的任何一个非零,则条件变为真。 (A || B)是真的。
! 称为逻辑非运算符。 用于反转其操作数的逻辑状态。 如果条件为真,则Logical NOT运算符将为false。 !(A && B)是真的。

下表显示了Go语言支持的所有逻辑运算符。 假设变量A保持为真,变量B保持为假,则 -

操作者 描述
&& 称为逻辑AND运算符。 如果两个操作数均为假,则条件变为false。 (A && B)是假的。
|| 称为逻辑OR运算符。 如果两个操作数中的任何一个为真,则条件成立。 (A || B)是真的。
! 称为逻辑非运算符。 用于反转其操作数的逻辑状态。 如果条件为真,则Logical NOT运算符将使其为false。 !(A && B)是真的。

按位运算符 (Bitwise Operators)

按位运算符处理位并执行逐位运算。 &,|和^的真值表如下 -

p q p&q p | q p ^ q
00000
01011
11110
10011

假设A = 60; 和B = 13.二进制格式,它们如下 -

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~A = 1100 0011

C语言支持的Bitwise运算符如下表所示。 假设变量A保持60,变量B保持13,则 -

显示示例

操作者 描述
& 如果二进制AND运算符存在于两个操作数中,则它会将结果复制到结果中。 (A&B)将给出12,即0000 1100
| 二进制OR运算符如果存在于任一操作数中,则复制一位。 (A | B)将给出61,即0011 1101
^ 二进制异或运算符如果在一个操作数中设置但不在两个操作数中设置,则复制该位。 (A ^ B)将给出49,即0011 0001
<< 二进制左移运算符。 左操作数值向左移动右操作数指定的位数。 A << 2将给出240,即1111 0000
>> 二进制右移运算符。 左操作数值向右移动右操作数指定的位数。 A >> 2将给出15,即0000 1111

赋值操作符 (Assignment Operators)

下表列出了Go语言支持的所有赋值运算符 -

显示示例

操作者 描述
= 简单赋值运算符,将右侧操作数的值分配给左侧操作数 C = A + B将A + B的值分配给C
+= 添加AND赋值运算符,它将右操作数添加到左操作数并将结果赋给左操作数 C + = A等于C = C + A.
-= 减去AND赋值运算符,它从左操作数中减去右操作数,并将结果赋给左操作数 C - = A相当于C = C - A.
*= 乘以AND赋值运算符,它将右操作数与左操作数相乘,并将结果赋值给左操作数 C * = A等于C = C * A.
/= 除法AND赋值运算符,它将左操作数除以右操作数,并将结果赋值给左操作数 C/= A相当于C = C/A.
%= 模数AND赋值运算符,使用两个操作数获取模数,并将结果赋给左操作数 C%= A等于C = C%A
<<= 左移AND赋值运算符 C << = 2与C = C << 2相同
>>= 右移AND赋值运算符 C >> = 2与C = C >> 2相同
&= 按位AND赋值运算符 C&= 2与C = C&2相同
^= 按位异或和赋值运算符 C ^ = 2与C = C ^ 2相同
|= 按位包含OR和赋值运算符 C | = 2与C = C |相同 2

混合操作符 (Miscellaneous Operators)

Go语言支持其他一些重要的运算符,包括sizeof?:.

显示示例

操作者 描述
& 返回变量的地址。 &一个; 提供变量的实际地址。
*Pointer to a variable. *一个; 提供指向变量的指针。

Go中的运算符优先级

运算符优先级确定表达式中的术语分组。 这会影响表达式的计算方式。 某些运算符的优先级高于其他运算符; 例如,乘法运算符的优先级高于加法运算符。

例如x = 7 + 3 * 2; 这里,x被赋值为13,而不是20,因为operator *的优先级高于+,所以它首先乘以3 * 2然后加到7中。

此处,具有最高优先级的运算符显示在表的顶部,具有最低优先级的运算符显示在底部。 在表达式中,将首先评估更高优先级的运算符。

显示示例

类别 操作者 关联性
Postfix ()[] - >。 ++ - - 左到右
Unary + - ! 〜++ - - (类型)*&sizeof 右到左
Multiplicative * /% 左到右
Additive + - 左到右
Shift << >> 左到右
Relational << => = 左到右
Equality ==!= 左到右
Bitwise AND& 左到右
Bitwise XOR ^ 左到右
Bitwise OR | 左到右
Logical AND && 左到右
Logical OR || 左到右
Conditional?: 右到左
Assignment = + = - = * =/=%= >> = << =&= ^ = | = 右到左
Comma, 左到右

Go - Decision Making

决策结构要求程序员指定一个或多个要由程序评估或测试的条件,以及在条件被确定为真时要执行的一个或多个语句,以及可选的,如果条件要执行的其他语句被认定是假的。

以下是大多数编程语言中常见决策结构的一般形式 -

Go中的决策声明

Go编程语言提供以下类型的决策制定语句。 单击以下链接以检查其详细信息。

Sr.No 声明和说明
1 if 语句

if statement由布尔表达式后跟一个或多个语句组成。

2 if...else 语句

if statement后面可以跟一个可选的else statement ,该else statement在布尔表达式为false时执行。

3 嵌套if语句

您可以在另一个ifelse if语句中使用ifelse if语句。

4 switch 语句

switch语句允许测试变量与值列表的相等性。

5 select statement

select语句类似于switch语句,区别在于case语句指的是通道通信。

Go - Loops

当您需要多次执行代码块时,可能会出现这种情况。 通常,语句按顺序执行:首先执行函数中的第一个语句,然后执行第二个语句,依此类推。

编程语言提供各种控制结构,允许更复杂的执行路径。

循环语句允许我们多次执行语句或语句组,以下是大多数编程语言中循环语句的一般形式 -

循环架构

Go编程语言提供以下类型的循环来处理循环要求。

Sr.No 循环类型和描述
1 for循环

它多次执行一系列语句,并缩写管理循环变量的代码。

2 嵌套循环

这些是任何for循环内的一个或多个循环。

循环控制语句 (Loop Control Statements)

循环控制语句将执行从其正常序列更改。 当执行离开其作用域时,将销毁在该作用域中创建的所有自动对象。

Go支持以下控制语句 -

Sr.No 控制声明和描述
1 break statement

它终止for loopswitch语句,并将执行转移到紧跟for循环或switch的语句之后。

2 continue statement

它导致循环跳过其身体的其余部分,并在重复之前立即重新测试其状态。

3 goto statement

它将控制转移到带标签的语句。

无限循环 (The Infinite Loop)

如果循环的条件永远不会变为假,则循环变为无限循环。 for循环传统上用于此目的。 由于不需要构成for循环的三个表达式,因此可以通过将条件表达式保留为空或将true传递给它来进行无限循环。

package main
import "fmt"
func main() {
   for true  {
       fmt.Printf("This loop will run forever.\n");
   }
}

当条件表达式不存在时,假定为真。 您可能有一个初始化和增量表达式,但C程序员更常使用for(;;)构造来表示无限循环。

Note - 您可以通过按Ctrl + C键终止无限循环。

Go - 函数

函数是一组一起执行任务的语句。 每个Go程序至少有一个函数,即main() 。 您可以将代码划分为单独的函数。 如何在不同的函数之间划分代码取决于您,但从逻辑上讲,划分应该是每个函数执行特定任务。

函数declaration告诉编译器有关函数名,返回类型和参数的信息。 函数definition提供函数的实际主体。

Go标准库提供了许多程序可以调用的内置函数。 例如,函数len()接受各种类型的参数并返回类型的长度。 如果传递一个字符串,该函数将返回字符串的长度(以字节为单位)。 如果向其传递数组,则该函数返回数组的长度。

函数也称为method, sub-routineprocedure

定义一个函数 (Defining a Function)

Go编程语言中函数定义的一般形式如下 -

func function_name( [parameter list] ) [return_types]
{
   body of the function
}

Go编程语言中的函数定义由function headerfunction body 。 以下是函数的所有部分 -

  • Func - 它开始声明一个函数。

  • Function Name - 它是Function Name的实际名称。 函数名称和参数列表一起构成函数签名。

  • Parameters - 参数类似于占位符。 调用函数时,将值传递给参数。 该值称为实际参数或参数。 参数列表是指函数参数的类型,顺序和数量。 参数是可选的; 也就是说,函数可能不包含任何参数。

  • Return Type - 函数可以返回值列表。 return_types是函数返回的值的数据类型列表。 某些函数执行所需的操作而不返回值。 在这种情况下,return_type不是必需的。

  • Function Body - 它包含一组语句,用于定义函数的功能。

例子 (Example)

以下源代码显示了一个名为max()的函数。 此函数接受两个参数num1和num2,并返回两者之间的最大值 -

/* function returning the max between two numbers */
func max(num1, num2 int) int {
   /* local variable declaration */
   result int
   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

调用一个函数 (Calling a Function)

在创建Go函数时,您可以定义函数必须执行的操作。 要使用函数,您必须调用该函数来执行定义的任务。

程序调用函数时,程序控制转移到被调用函数。 被调用的函数执行已定义的任务,当执行其return语句或达到其函数结束的右括号时,它将程序控制返回给主程序。

要调用函数,只需传递必需的参数及其函数名称即可。 如果函数返回一个值,则可以存储返回的值。 例如 -

package main
import "fmt"
func main() {
   /* local variable definition */
   var a int = 100
   var b int = 200
   var ret int
   /* calling a function to get max value */
   ret = max(a, b)
   fmt.Printf( "Max value is : %d\n", ret )
}
/* function returning the max between two numbers */
func max(num1, num2 int) int {
   /* local variable declaration */
   var result int
   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

我们将max()函数与main()函数一起保存并编译源代码。 在运行最终可执行文件时,它会产生以下结果 -

Max value is : 200

从Function返回多个值

Go函数可以返回多个值。 例如 -

package main
import "fmt"
func swap(x, y string) (string, string) {
   return y, x
}
func main() {
   a, b := swap("Mahesh", "Kumar")
   fmt.Println(a, b)
}

编译并执行上述代码时,会产生以下结果 -

Kumar Mahesh

函数参数(Function Arguments)

如果函数是使用参数,它必须声明接受参数值的变量。 这些变量称为函数的formal parameters

形式参数的行为与函数内部的其他局部变量相似,并在进入函数时创建,并在退出时销毁。

在调用函数时,有两种方法可以将参数传递给函数 -

Sr.No 通话类型和说明
1 Call by value

此方法将参数的实际值复制到函数的形式参数中。 在这种情况下,对函数内部参数所做的更改不会对参数产生影响。

2 Call by reference

此方法将参数的地址复制到形式参数中。 在函数内部,该地址用于访问调用中使用的实际参数。 这意味着对参数所做的更改会影响参数。

默认情况下,Go使用call by value来传递参数。 通常,它意味着函数内的代码不能改变用于调用函数的参数。 上面的程序在调用max()函数时使用了相同的方法。

功能用法

可以通过以下方式使用函数:

Sr.No 功能用法和说明
1 Function as Value

可以动态创建函数,并可以将其用作值。

2 Function Closures

函数闭包是匿名函数,可用于动态编程。

3 Method

方法是带接收器的特殊功能。

Go - Scope Rules

任何编程中的范围都是程序的一个区域,其中可以存在已定义的变量,并且不能访问该变量。 有三个地方可以用Go编程语言声明变量 -

  • 在函数或块内( local变量)

  • 所有函数之外( global变量)

  • 在函数参数的定义中( formal参数)

让我们找出什么是localglobal变量以及什么是formal参数。

局部变量 (Local Variables)

在函数或块内声明的变量称为局部变量。 它们只能由该函数或代码块中的语句使用。 本地变量不为其自身以外的函数所知。 以下示例使用局部变量。 这里所有变量a,b和c都是main()函数的局部变量。

package main
import "fmt"
func main() {
   /* local variable declaration */
   var a, b, c int 
   /* actual initialization */
   a = 10
   b = 20
   c = a + b
   fmt.Printf ("value of a = %d, b = %d and c = %d\n", a, b, c)
}

编译并执行上述代码时,会产生以下结果 -

value of a = 10, b = 20 and c = 30

全局变量 (Global Variables)

全局变量在函数之外定义,通常在程序之上。 全局变量在程序的整个生命周期中都保持其值,并且可以在为程序定义的任何函数内访问它们。

任何函数都可以访问全局变量。 也就是说,一个全局变量在声明之后可以在整个程序中使用。 以下示例使用全局变量和局部变量 -

package main
import "fmt"
/* global variable declaration */
var g int
func main() {
   /* local variable declaration */
   var a, b int
   /* actual initialization */
   a = 10
   b = 20
   g = a + b
   fmt.Printf("value of a = %d, b = %d and g = %d\n", a, b, g)
}

编译并执行上述代码时,会产生以下结果 -

value of a = 10, b = 20 and g = 30

程序可以具有本地和全局变量的相同名称,但函数内的局部变量的值优先。 例如 -

package main
import "fmt"
/* global variable declaration */
var g int = 20
func main() {
   /* local variable declaration */
   var g int = 10
   fmt.Printf ("value of g = %d\n",  g)
}

编译并执行上述代码时,会产生以下结果 -

value of g = 10

形式参数

正式参数被视为具有该函数的局部变量,并且它们优先于全局变量。 例如 -

package main
import "fmt"
/* global variable declaration */
var a int = 20;
func main() {
   /* local variable declaration in main function */
   var a int = 10
   var b int = 20
   var c int = 0
   fmt.Printf("value of a in main() = %d\n",  a);
   c = sum( a, b);
   fmt.Printf("value of c in main() = %d\n",  c);
}
/* function to add two integers */
func sum(a, b int) int {
   fmt.Printf("value of a in sum() = %d\n",  a);
   fmt.Printf("value of b in sum() = %d\n",  b);
   return a + b;
}

编译并执行上述代码时,会产生以下结果 -

value of a in main() = 10
value of a in sum() = 10
value of b in sum() = 20
value of c in main() = 30

初始化本地和全局变量

局部变量和全局变量初始化为其默认值,即0; 而指针初始化为nil。

数据类型 初始默认值
int0
float320
pointernil

Go - Strings

在Go编程中广泛使用的字符串是一个只读字节。 在Go编程语言中,字符串是slices 。 Go平台提供了各种库来操作字符串。

  • unicode
  • regexp
  • strings

创建字符串

创建字符串的最直接方法是写 -

var greeting = "Hello world!"

每当它遇到代码中的字符串文字时,编译器就会创建一个字符串对象,其值在这种情况下为“Hello world!”。

字符串文字包含一个名为符文的有效UTF-8序列。 String保存任意字节。

package main
import "fmt"
func main() {
   var greeting =  "Hello world!"
   fmt.Printf("normal string: ")
   fmt.Printf("%s", greeting)
   fmt.Printf("\n")
   fmt.Printf("hex bytes: ")
   for i := 0; i < len(greeting); i++ {
       fmt.Printf("%x ", greeting[i])
   }
   fmt.Printf("\n")
   const sampleText = "\xbd\xb2\x3d\xbc\x20\xe2\x8c\x98" 
   /*q flag escapes unprintable characters, with + flag it escapses non-ascii 
   characters as well to make output unambigous  
   */
   fmt.Printf("quoted string: ")
   fmt.Printf("%+q", sampleText)
   fmt.Printf("\n")  
}

这会产生以下结果 -

normal string: Hello world!
hex bytes: 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 
quoted string: "\xbd\xb2=\xbc \u2318"

Note - 字符串文字是不可变的,因此一旦创建,就无法更改字符串文字。

String Length

len(str)方法返回字符串文字中包含的字节数。

package main
import "fmt"
func main() {
   var greeting =  "Hello world!"
   fmt.Printf("String Length is: ")
   fmt.Println(len(greeting))  
}

这会产生以下结果 -

String Length is : 12

连接字符串

strings包包含用于连接多个字符串的方法join -

strings.Join(sample, " ")

Join连接数组的元素以创建单个字符串。 第二个参数是位于数组元素之间的分隔符。

让我们看看下面的例子 -

package main
import ("fmt" "math" )"fmt" "strings")
func main() {
   greetings :=  []string{"Hello","world!"}   
   fmt.Println(strings.Join(greetings, " "))
}

这会产生以下结果 -

Hello world!

Go - Arrays

Go编程语言提供了一种称为the array的数据结构,它可以存储固定大小的相同类型元素的顺序集合。 数组用于存储数据集合,但将数组视为相同类型的变量集合通常更有用。

您可以声明一个数组变量(例如数字)并使用数字[0],数字[1]和...,数字[99]来表示单个变量,例如number0,number1,...和number99,而不是声明单个变量。个别变数。 索引访问数组中的特定元素。

所有阵列都包含连续的内存位置。 最低地址对应于第一个元素,最高地址对应于最后一个元素。

Go中的数组

声明数组 (Declaring Arrays)

要在Go中声明一个数组,程序员指定元素的类型和数组所需的元素数量,如下所示 -

var variable_name [SIZE] variable_type

这称为一single-dimensional数组。 arraySize必须是大于零的整数常量, type可以是任何有效的Go数据类型。 例如,要声明一个名为balance32的float元素的10元素数组,请使用此语句 -

var balance [10] float32

这里, balance是一个可以容纳10个浮点数的变量数组。

初始化数组 (Initializing Arrays)

您可以逐个初始化Go中的数组,也可以使用单个语句,如下所示 -

var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

大括号{}之间的值的数量不能大于我们在方括号[]之间为数组声明的元素的数量。

如果省略数组的大小,则会创建一个足以容纳初始化的数组。 因此,如果你写 -

var balance = []float32{1000.0, 2.0, 3.4, 7.0, 50.0}

您将创建与上一示例中完全相同的阵列。 以下是分配数组的单个元素的示例 -

balance[4] = 50.0

上面的语句在数组中为元素编号5指定了值50.0。 所有数组都将0作为其第一个元素的索引,也称为基本索引,数组的最后一个索引将是数组的总大小减去1.以下是我们上面讨论的相同数组的图形表示 -

阵列演示

访问数组元素 (Accessing Array Elements)

通过索引数组名称来访问元素。 这是通过将元素的索引放在数组名称后面的方括号中来完成的。 例如 -

float32 salary = balance[9]

上面的语句将从数组中取出 10 元素,并将值赋给salary变量。 以下是一个使用上述三个概念的例子。 声明,分配和访问数组 -

package main
import "fmt"
func main() {
   var n [10]int /* n is an array of 10 integers */
   var i,j int
   /* initialize elements of array n to 0 */         
   for i = 0; i < 10; i++ {
      n[i] = i + 100 /* set element at location i to i + 100 */
   }
   /* output each array element's value */
   for j = 0; j < 10; j++ {
      fmt.Printf("Element[%d] = %d\n", j, n[j] )
   }
}

编译并执行上述代码时,会产生以下结果 -

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

详细Go阵列

有一些与数组相关的重要概念对于Go程序员来说应该是清楚的 -

Sr.No 概念与描述
1 多维数组

Go支持多维数组。 多维数组的最简单形式是二维数组。

2 将数组传递给函数

您可以通过指定不带索引的数组名称来向函数传递指向数组的指针。

Go - Pointers

Go中的指针简单易学。 使用指针可以更轻松地执行某些Go编程任务,而不使用指针就无法执行其他任务(如通过引用调用)。 所以有必要学习指向成为一个完美的Go程序员。

如您所知,每个变量都是一个内存位置,每个内存位置都定义了其地址,可以使用和号(&)运算符进行访问,该运算符表示内存中的地址。 考虑以下示例,它将打印定义的变量的地址 -

package main
import "fmt"
func main() {
   var a int = 10   
   fmt.Printf("Address of a variable: %x\n", &a  )
}

编译并执行上述代码时,会产生以下结果 -

Address of a variable: 10328000

所以你了解什么是内存地址以及如何访问它。 现在让我们看看指针是什么。

什么是指针?

pointer是一个变量,其值是另一个变量的地址,即存储器位置的直接地址。 与任何变量或常量一样,必须先声明指针,然后才能使用它来存储任何变量地址。 指针变量声明的一般形式是 -

var var_name *var-type

这里, type是指针的基类型; 它必须是有效的C数据类型, var-name是指针变量的名称。 用于声明指针的星号*与用于乘法的星号相同。 但是,在此语句中,星号用于将变量指定为指针。 以下是有效的指针声明 -

var ip *int        /* pointer to an integer */
var fp *float32    /* pointer to a float */

所有指针的值的实际数据类型,无论是整数,浮点还是其他,都是相同的,是表示内存地址的长十六进制数。 不同数据类型的指针之间的唯一区别是指针指向的变量或常量的数据类型。

如何使用指针?

有一些重要的操作,我们经常使用指针执行:(a)我们定义指针变量,(b)将变量的地址分配给指针,以及(c)访问存储在指针变量中的地址的值。

所有这些操作都使用一元运算符*来执行,该运算符*返回位于其操作数指定的地址处的变量的值。 以下示例演示了如何执行这些操作 -

package main
import "fmt"
func main() {
   var a int = 20   /* actual variable declaration */
   var ip *int      /* pointer variable declaration */
   ip = &a  /* store address of a in pointer variable*/
   fmt.Printf("Address of a variable: %x\n", &a  )
   /* address stored in pointer variable */
   fmt.Printf("Address stored in ip variable: %x\n", ip )
   /* access the value using the pointer */
   fmt.Printf("Value of *ip variable: %d\n", *ip )
}

编译并执行上述代码时,会产生以下结果 -

Address of var variable: 10328000
Address stored in ip variable: 10328000
Value of *ip variable: 20

Go中没有指针

如果您没有要分配的确切地址,Go编译器会将Nil值分配给指针变量。 这是在变量声明时完成的。 指定为nil指针称为nil指针。

nil指针是一个常量,在几个标准库中定义了零值。 考虑以下程序 -

package main
import "fmt"
func main() {
   var  ptr *int
   fmt.Printf("The value of ptr is : %x\n", ptr  )
}

编译并执行上述代码时,会产生以下结果 -

The value of ptr is 0

在大多数操作系统上,程序不允许访问地址0处的内存,因为该内存是由操作系统保留的。 但是,存储器地址0具有特殊意义; 它表示指针不是指向可访问的内存位置。 但按照惯例,如果指针包含nil(零)值,则假定它指向任何值。

要检查nil指针,可以使用if语句,如下所示 -

if(ptr != nil)     /* succeeds if p is not nil */
if(ptr == nil)    /* succeeds if p is null */

Go指针细节

指针有许多但很简单的概念,它们对Go编程非常重要。 Go程序员应该清楚以下指针概念 -

Sr.No 概念与描述
1 Go - 指针数组

您可以定义数组以包含许多指针。

2 Go - 指向指针

Go允许您在指针上指针等等。

3 将指针传递给Go中的函数

通过引用或地址传递参数都可以通过被调用函数在调用函数中更改传递的参数。

Go - Structures

Go数组允许您定义可以包含多个相同类型的数据项的变量。 Structure是Go编程中另一种用户定义的数据类型,它允许您组合不同类型的数据项。

结构用于表示记录。 假设您想要跟踪库中的书籍。 您可能希望跟踪每本书的以下属性 -

  • Title
  • Author
  • Subject
  • Book ID

在这种情况下,结构非常有用。

定义一个结构 (Defining a Structure)

要定义结构,必须使用typestruct语句。 struct语句定义了一个新的数据类型,为您的程序提供了多个成员。 type语句使用我们的case中的struct类型绑定一个名称。 struct语句的格式如下 -

type struct_variable_type struct {
   member definition;
   member definition;
   ...
   member definition;
}

定义结构类型后,可以使用以下语法声明该类型的变量。

variable_name := structure_variable_type {value1, value2...valuen}

访问结构成员 (Accessing Structure Members)

要访问结构的任何成员,我们使用member access operator (.). 成员访问运算符被编码为结构变量名称和我们希望访问的结构成员之间的句点。 您可以使用struct关键字来定义结构类型的变量。 以下示例说明如何使用结构 -

package main
import "fmt"
type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
   var Book1 Books    /* Declare Book1 of type Book */
   var Book2 Books    /* Declare Book2 of type Book */
   /* book 1 specification */
   Book1.title = "Go Programming"
   Book1.author = "Mahesh Kumar"
   Book1.subject = "Go Programming Tutorial"
   Book1.book_id = 6495407
   /* book 2 specification */
   Book2.title = "Telecom Billing"
   Book2.author = "Zara Ali"
   Book2.subject = "Telecom Billing Tutorial"
   Book2.book_id = 6495700
   /* print Book1 info */
   fmt.Printf( "Book 1 title : %s\n", Book1.title)
   fmt.Printf( "Book 1 author : %s\n", Book1.author)
   fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
   fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)
   /* print Book2 info */
   fmt.Printf( "Book 2 title : %s\n", Book2.title)
   fmt.Printf( "Book 2 author : %s\n", Book2.author)
   fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
   fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}

编译并执行上述代码时,会产生以下结果 -

Book 1 title      : Go Programming
Book 1 author     : Mahesh Kumar
Book 1 subject    : Go Programming Tutorial
Book 1 book_id    : 6495407
Book 2 title      : Telecom Billing
Book 2 author     : Zara Ali
Book 2 subject    : Telecom Billing Tutorial
Book 2 book_id    : 6495700

作为函数参数的结构 (Structures as Function Arguments)

您可以将结构作为函数参数传递,与传递任何其他变量或指针的方式非常相似。 您将以与上例中相同的方式访问结构变量 -

package main
import "fmt"
type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
   var Book1 Books    /* Declare Book1 of type Book */
   var Book2 Books    /* Declare Book2 of type Book */
   /* book 1 specification */
   Book1.title = "Go Programming"
   Book1.author = "Mahesh Kumar"
   Book1.subject = "Go Programming Tutorial"
   Book1.book_id = 6495407
   /* book 2 specification */
   Book2.title = "Telecom Billing"
   Book2.author = "Zara Ali"
   Book2.subject = "Telecom Billing Tutorial"
   Book2.book_id = 6495700
   /* print Book1 info */
   printBook(Book1)
   /* print Book2 info */
   printBook(Book2)
}
func printBook( book Books ) {
   fmt.Printf( "Book title : %s\n", book.title);
   fmt.Printf( "Book author : %s\n", book.author);
   fmt.Printf( "Book subject : %s\n", book.subject);
   fmt.Printf( "Book book_id : %d\n", book.book_id);
}

编译并执行上述代码时,会产生以下结果 -

Book title     : Go Programming
Book author    : Mahesh Kumar
Book subject   : Go Programming Tutorial
Book book_id   : 6495407
Book title     : Telecom Billing
Book author    : Zara Ali
Book subject   : Telecom Billing Tutorial
Book book_id   : 6495700

指向结构的指针

您可以使用与定义指向任何其他变量的指针相同的方式定义指向结构的指针,如下所示 -

var struct_pointer *Books

现在,您可以将结构变量的地址存储在上面定义的指针变量中。 要查找结构变量的地址,请将&运算符放在结构名称之前,如下所示 -

struct_pointer = &Book1;

要使用指向该结构的指针访问结构的成员,必须使用“。”。 运算符如下 -

struct_pointer.title;

让我们使用结构指针重写上面的例子 -

package main
import "fmt"
type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
   var Book1 Books   /* Declare Book1 of type Book */
   var Book2 Books   /* Declare Book2 of type Book */
   /* book 1 specification */
   Book1.title = "Go Programming"
   Book1.author = "Mahesh Kumar"
   Book1.subject = "Go Programming Tutorial"
   Book1.book_id = 6495407
   /* book 2 specification */
   Book2.title = "Telecom Billing"
   Book2.author = "Zara Ali"
   Book2.subject = "Telecom Billing Tutorial"
   Book2.book_id = 6495700
   /* print Book1 info */
   printBook(&Book1)
   /* print Book2 info */
   printBook(&Book2)
}
func printBook( book *Books ) {
   fmt.Printf( "Book title : %s\n", book.title);
   fmt.Printf( "Book author : %s\n", book.author);
   fmt.Printf( "Book subject : %s\n", book.subject);
   fmt.Printf( "Book book_id : %d\n", book.book_id);
}

编译并执行上述代码时,会产生以下结果 -

Book title     : Go Programming
Book author    : Mahesh Kumar
Book subject   : Go Programming Tutorial
Book book_id   : 6495407
Book title     : Telecom Billing
Book author    : Zara Ali
Book subject   : Telecom Billing Tutorial
Book book_id   : 6495700

Go - Slices

Go Slice是Go Array的抽象。 Go Array允许您定义可以包含多个同类数据项的变量,但它不提供任何内置方法来动态增加其大小或获取自己的子数组。 切片克服了这个限制。 它提供了Array所需的许多实用功能,并广泛用于Go编程。

定义切片

要定义切片,可以将其声明为数组而不指定其大小。 或者,您可以使用make函数创建切片。

var numbers []int /* a slice of unspecified size */
/* numbers == []int{0,0,0,0,0}*/
numbers = make([]int,5,5) /* a slice of length 5 and capacity 5*/

len() and cap() 函数

切片是数组的抽象。 它实际上使用数组作为底层结构。 len()函数返回切片中的元素,其中cap()函数返回切片的容量(即,它可以容纳多少元素)。 以下示例解释了切片的用法 -

package main
import "fmt"
func main() {
   var numbers = make([]int,3,5)
   printSlice(numbers)
}
func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

编译并执行上述代码时,会产生以下结果 -

len = 3 cap = 5 slice = [0 0 0]

零切片

如果声明切片没有输入,则默认情况下,它被初始化为nil。 它的长度和容量为零。 例如 -

package main
import "fmt"
func main() {
   var numbers []int
   printSlice(numbers)
   if(numbers == nil){
      fmt.Printf("slice is nil")
   }
}
func printSlice(x []int){
   fmt.Printf("len = %d cap = %d slice = %v\n", len(x), cap(x),x)
}

编译并执行上述代码时,会产生以下结果 -

len = 0 cap = 0 slice = []
slice is nil

Subslicing

Slice允许使用[lower-bound:upper-bound]指定下限和上限来获取它的子切片。 例如 -

package main
import "fmt"
func main() {
   /* create a slice */
   numbers := []int{0,1,2,3,4,5,6,7,8}   
   printSlice(numbers)
   /* print the original slice */
   fmt.Println("numbers ==", numbers)
   /* print the sub slice starting from index 1(included) to index 4(excluded)*/
   fmt.Println("numbers[1:4] ==", numbers[1:4])
   /* missing lower bound implies 0*/
   fmt.Println("numbers[:3] ==", numbers[:3])
   /* missing upper bound implies len(s)*/
   fmt.Println("numbers[4:] ==", numbers[4:])
   numbers1 := make([]int,0,5)
   printSlice(numbers1)
   /* print the sub slice starting from index 0(included) to index 2(excluded) */
   number2 := numbers[:2]
   printSlice(number2)
   /* print the sub slice starting from index 2(included) to index 5(excluded) */
   number3 := numbers[2:5]
   printSlice(number3)
}
func printSlice(x []int){
   fmt.Printf("len = %d cap = %d slice = %v\n", len(x), cap(x),x)
}

编译并执行上述代码时,会产生以下结果 -

len = 9 cap = 9 slice = [0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len = 0 cap = 5 slice = []
len = 2 cap = 9  slice = [0 1]
len = 3 cap = 7 slice = [2 3 4]

append() and copy() 函数

可以使用append()函数增加切片的容量。 使用copy()函数,源片的内容将复制到目标片。 例如 -

package main
import "fmt"
func main() {
   var numbers []int
   printSlice(numbers)
   /* append allows nil slice */
   numbers = append(numbers, 0)
   printSlice(numbers)
   /* add one element to slice*/
   numbers = append(numbers, 1)
   printSlice(numbers)
   /* add more than one element at a time*/
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)
   /* create a slice numbers1 with double the capacity of earlier slice*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)
   /* copy content of numbers to numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)   
}
func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

编译并执行上述代码时,会产生以下结果 -

len = 0 cap = 0 slice = []
len = 1 cap = 2 slice = [0]
len = 2 cap = 2 slice = [0 1]
len = 5 cap = 8 slice = [0 1 2 3 4]
len = 5 cap = 16 slice = [0 1 2 3 4]

Go - Range

range关键字在for循环中用于迭代数组,切片,通道或映射的项。 对于数组和切片,它将项的索引作为整数返回。 使用地图,它返回下一个键值对的键。 范围返回一个值或两个值。 如果在范围表达式的左侧仅使用一个值,则它是下表中的第一个值。

范围表达 第一价值 第二个值(可选)
数组或切片a [n] E. index i int a [i] E
字符串的字符串类型 index i int rune int
map m map [K] V 键k K. 值m [k] V.
频道c chan E. 元素e E. none

例子 (Example)

以下段落显示如何使用范围 -

package main
import "fmt"
func main() {
   /* create a slice */
   numbers := []int{0,1,2,3,4,5,6,7,8} 
   /* print the numbers */
   for i:= range numbers {
      fmt.Println("Slice item",i,"is",numbers[i])
   }
   /* create a map*/
   countryCapitalMap := map[string] string {"France":"Paris","Italy":"Rome","Japan":"Tokyo"}
   /* print map using keys*/
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
   /* print map using key-value*/
   for country,capital := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",capital)
   }
}

编译并执行上述代码时,会产生以下结果 -

Slice item 0 is 0
Slice item 1 is 1
Slice item 2 is 2
Slice item 3 is 3
Slice item 4 is 4
Slice item 5 is 5
Slice item 6 is 6
Slice item 7 is 7
Slice item 8 is 8
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo

Go - Maps

Go提供了另一种名为map的重要数据类型,它将唯一键映射到值。 键是用于在以后检索值的对象。 给定键和值,您可以将值存储在Map对象中。 存储该值后,您可以使用其密钥检索它。

定义地图

您必须使用make函数来创建地图。

/* declare a variable, by default map will be nil*/
var map_variable map[key_data_type]value_data_type
/* define the map as nil map can not be assigned any value*/
map_variable = make(map[key_data_type]value_data_type)

例子 (Example)

以下示例说明了如何创建和使用地图 -

package main
import "fmt"
func main() {
   var countryCapitalMap map[string]string
   /* create a map*/
   countryCapitalMap = make(map[string]string)
   /* insert key-value pairs in the map*/
   countryCapitalMap["France"] = "Paris"
   countryCapitalMap["Italy"] = "Rome"
   countryCapitalMap["Japan"] = "Tokyo"
   countryCapitalMap["India"] = "New Delhi"
   /* print map using keys*/
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
   /* test if entry is present in the map or not*/
   capital, ok := countryCapitalMap["United States"]
   /* if ok is true, entry is present otherwise entry is absent*/
   if(ok){
      fmt.Println("Capital of United States is", capital)  
   } else {
      fmt.Println("Capital of United States is not present") 
   }
}

编译并执行上述代码时,会产生以下结果 -

Capital of India is New Delhi
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of United States is not present

delete() Function

delete()函数用于从地图中删除条目。 它需要地图和要删除的相应密钥。 例如 -

package main
import "fmt"
func main() {   
   /* create a map*/
   countryCapitalMap := map[string] string {"France":"Paris","Italy":"Rome","Japan":"Tokyo","India":"New Delhi"}
   fmt.Println("Original map")   
   /* print map */
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
   /* delete an entry */
   delete(countryCapitalMap,"France");
   fmt.Println("Entry for France is deleted")  
   fmt.Println("Updated map")   
   /* print map */
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
}

编译并执行上述代码时,会产生以下结果 -

Original Map
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi
Entry for France is deleted
Updated Map
Capital of India is New Delhi
Capital of Italy is Rome
Capital of Japan is Tokyo

Go - Recursion

递归是以自相似的方式重复项目的过程。 同样的概念也适用于编程语言。 如果程序允许在同一函数内调用函数,则称其为递归函数调用。 看看下面的例子 -

func recursion() {
   recursion() /* function calls itself */
}
func main() {
   recursion()
}

Go编程语言支持递归。 也就是说,它允许函数调用自身。 但是在使用递归时,程序员需要小心地从函数中定义退出条件,否则它将继续成为无限循环。

Go中的递归示例

递归函数对于解决许多数学问题非常有用,例如计算数的阶乘,生成Fibonacci序列等。

示例1:使用Go中的递归计算因子

以下示例使用递归函数计算给定数字的阶乘 -

package main
import "fmt"
func factorial(i int)int {
   if(i <= 1) {
      return 1
   }
   return i * factorial(i - 1)
}
func main() { 
   var i int = 15
   fmt.Printf("Factorial of %d is %d", i, factorial(i))
}

编译并执行上述代码时,会产生以下结果 -

Factorial of 15 is 2004310016

例2:在Go中使用递归的Fibonacci系列

以下示例显示如何使用递归函数生成给定数字的Fibonacci系列 -

package main
import "fmt"
func fibonaci(i int) (ret int) {
   if i == 0 {
      return 0
   }
   if i == 1 {
      return 1
   }
   return fibonaci(i-1) + fibonaci(i-2)
}
func main() {
   var i int
   for i = 0; i < 10; i++ {
      fmt.Printf("%d ", fibonaci(i))
   }
}

编译并执行上述代码时,会产生以下结果 -

0 1 1 2 3 5 8 13 21 34 

Go - Type Casting

类型转换是一种将变量从一种数据类型转换为另一种数据类型的方法。 例如,如果要将long值存储到简单整数中,则可以将cast long类型设置为int。 您可以使用强制转换cast operator将值从一种类型转换为另一种类型。 其语法如下 -

type_name(expression)

例子 (Example)

考虑以下示例,其中强制转换运算符导致一个整数变量除以另一个整数变量作为浮点数运算执行。

package main
import "fmt"
func main() {
   var sum int = 17
   var count int = 5
   var mean float32
   mean = float32(sum)/float32(count)
   fmt.Printf("Value of mean : %f\n",mean)
}

编译并执行上述代码时,会产生以下结果 -

Value of mean : 3.400000

Go - Interfaces

Go编程提供了另一种称为interfaces数据类型,它代表一组方法签名。 struct数据类型实现这些接口以具有接口的方法签名的方法定义。

语法 (Syntax)

/* define an interface */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}
/* define a struct */
type struct_name struct {
   /* variables */
}
/* implement interface methods*/
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* method implementation */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* method implementation */
}

例子 (Example)

package main
import (
   "fmt" 
   "math" 
)
/* define an interface */
type Shape interface {
   area() float64
}
/* define a circle */
type Circle struct {
   x,y,radius float64
}
/* define a rectangle */
type Rectangle struct {
   width, height float64
}
/* define a method for circle (implementation of Shape.area())*/
func(circle Circle) area() float64 {
   return math.Pi * circle.radius * circle.radius
}
/* define a method for rectangle (implementation of Shape.area())*/
func(rect Rectangle) area() float64 {
   return rect.width * rect.height
}
/* define a method for shape */
func getArea(shape Shape) float64 {
   return shape.area()
}
func main() {
   circle := Circle{x:0,y:0,radius:5}
   rectangle := Rectangle {width:10, height:5}
   fmt.Printf("Circle area: %f\n",getArea(circle))
   fmt.Printf("Rectangle area: %f\n",getArea(rectangle))
}

编译并执行上述代码时,会产生以下结果 -

Circle area: 78.539816
Rectangle area: 50.000000

Go - Error Handling

Go编程提供了一个非常简单的错误处理框架,具有以下声明的内置错误接口类型 -

type error interface {
   Error() string
}

函数通常返回错误作为最后返回值。 使用errors.New构建基本错误消息如下 -

func Sqrt(value float64)(float64, error) {
   if(value < 0){
      return 0, errors.New("Math: negative number passed to Sqrt")
   }
   return math.Sqrt(value)
}

使用返回值和错误消息。

result, err:= Sqrt(-1)
if err != nil {
   fmt.Println(err)
}

例子 (Example)

package main
import "errors"
import "fmt"
import "math"
func Sqrt(value float64)(float64, error) {
   if(value < 0){
      return 0, errors.New("Math: negative number passed to Sqrt")
   }
   return math.Sqrt(value), nil
}
func main() {
   result, err:= Sqrt(-1)
   if err != nil {
      fmt.Println(err)
   } else {
      fmt.Println(result)
   }
   result, err = Sqrt(9)
   if err != nil {
      fmt.Println(err)
   } else {
      fmt.Println(result)
   }
}

编译并执行上述代码时,会产生以下结果 -

Math: negative number passed to Sqrt
3
↑回到顶部↑
WIKI教程 @2018