您的位置首页  网络科技  前端

WEB前端线最新-白水明田外碧峰出山后

  在之前的学习之后,我们已经配置了环境。现在,我们将学习Go语言的特点以及如何最好地使用它。在找到“最佳”方法之前,有一个首要原则:以一种明确表达意图的方式编写代码。在解释这些特性的过程中,我们将看看哪些选项以及为什么某种方法可以产生更干净的代码。我们将首先学习基本类型和变量。虽然每个程序员都有这些概念,但是Go在某些方面是不一样的,Go和其他语言也有一些细微的区别。Go和其他语言一样,有一些内置的类型:Boolean、integer、floating-point和string。对于从其他语言移植过来的开发人员来说,正确使用这些类型有时很有挑战性。我们将讨论这些类型以及如何在围棋中最好地使用它们。在学习这些类型之前,我们先解释一下适用于所有类型的一些概念。像大多数现代语言一样,Go将声明为未赋值的变量默认为零值。显式零值可以使代码更干净,并消除C和C++程序中的错误。在谈到每一种类型时,都会顺便提到这几种类型的零值。

  Go中的文字量代表书写的数字、字符或字符串。Go程序中常见的文字有四种(讨论复数时会提到第五种不常见的文字)。整数是一组数字,通常是十进制,但其他前缀可以用不同的前缀表示:0b是二进制,0o是八进制,0x是十六进制。前缀可以使用大写字母或小写字母。在前面加0,后面不加任何字母是另一种表达八进制文字的方式。但是不建议,会导致误解。为了更容易阅读更长的整数文字,Go允许我们在文字中间添加下划线。例如,我们可以以千为单位对十进制数进行分组(1_234)。这些下划线对数值没有影响。唯一的限制是下划线不能放在数字的开头和结尾,并且下划线不能与下划线相连。可以在字面量的每个数字之间加一个下划线),但不建议这样做。十进制数由千位分隔,或者二进制、八进制和十六进制数由一个字节、两个字节或四个字节分隔,以提高可读性。文字浮点数包含小数点来表示小数位。您也可以使用字母E加上一个正数或负数来表示指数(例如6.03e23)。也可以用0x写十六进制,用字母P代表指数。与整数文字相似,您可以使用下划线来格式化浮点文字。符文的字面量由单引号包围的字符表示。与许多其他语言不同,Go语言中的单引号和双引号并不通用。符文文字可以写成单个Unicode字符( a )、8个八位字节( \141 )、8个十六进制数字( \x61 )、16个十六进制数字( \u0061 )或32个Unicode数字( \ u0000061 )。还有一些反斜杠转义符文字符,最有用的有换行符( \n )、制表符( \t )、单引号( \ )、双引号( \ )和反斜杠( \ \ )。在实践中,我们用十进制来表示符文文字的数字。除非使用十六进制转义能让代码更整洁,否则请避免使用。八进制的使用很少,大部分是用来表示POSIX权限标记的(比如rwxrwxrwx的0o777)。有时十六进制和二进制用于位过滤或网络和基础设施应用。

  有两种方法来表达一个字符串的字面量。大多数情况下,应该使用字面解释字符串(如输入**“问候和**问候”)。它们以允许的形式包含零个或多个runic文字。不能使用的字符是未转义的反斜杠、换行符和双引号。如果您使用解释字符串文字,并希望两个问候语在不同的行上,而问候语在双引号中,则需要输入* * 问候语和\ n \ 问候语\ * *。如果需要在字符串中使用反斜杠、换行符和双引号,也可以使用原生字符串文字。使用反引号(````)作为分隔符,它可以包含反引号以外的任何字符。使用原生字符串文字时,多行问候语可以写成这样:`问候和“致敬”复制代码在显示类型转换一节中,您将了解到,如果声明的内存大小不同,即使是两个整数变量也不能相加。但是Go允许我们在浮点表达式中使用整数文字,甚至将整数文字赋给浮点变量。这是因为Go中的文本没有类型,可以与任何与该文本兼容的变量一起使用。我们将在“类型、方法和接口”一章中看到,我们甚至可以使用基于基本类型的自定义类型。没有类型只能这样。不能将字符串文字赋给数值类型变量,不能将数值文字赋给字符串变量,也不能将浮点文字赋给整数类型。这些编译被认为是错误。字面量是非类型化的,因为Go是一种实用语言。在开发人员指定类型之前,不强制任何类型是可行的。内存大小有限制。尽管整数可以用它所能存储的大数字来写,但是当被赋值的文字导致特定变量溢出时,会出现编译时错误,例如将1000的文字赋给byte类型的变量。正如您将在变量赋值一节中了解到的那样,在Go语言中有一些场景中,类型不是显式声明的。此时Go使用默认类型的字面量;如果不能在表达式中明确指出文本类型,默认情况下将使用文本类型。我们在学习各种内置类型的时候会讲到文字量的默认类型。布尔型bool类型表示布尔变量。bool类型的变量可以是以下两个值之一:true或false。bool的零值为假:Var标志bool // Unassigned,设置为falsevar isAwesome = true复制代码没有变量声明就很难讨论变量类型,反之亦然。我们将首先使用变量声明,这在**var comparison: = * *一节中有描述。数字类型围棋有很多种数:三大类十二种(还有一些特殊的名字)。如果读者是从JavaScript这种只有一种数字类型的语言中转过来的,可能会觉得太多了。但实际上常用的只有几类,其他的很少用。我们将讨论整数,然后我们将继续讨论很少使用的浮点和复杂类型。整数Go提供不同类型和大小的有符号和无符号整数,大小从1字节到8字节不等。请参见下表:表2-1 GO语言中的整数类型值范围int 8–128到127 int 16–32768到32767 int 32–2147483648到2147483647 int 64–808到07 uint 80到2555 uint 160到65535ui nt320到429496720名字应该很清楚。所有整数的零值都是0。特殊整数Go integer有一些特殊的名字。Byte是uint8的别名,对byte和uint8进行赋值、比较或执行数算是合法的。但在Go代码中很少看到uint8的使用,直接调用byte。第二个特殊的名字是int。在32位CPU中,int是32位有符号整数,与int32相同。在大多数64位CPU中,int都是64位有符号整数,与int64相同。因为int在不同平台上不一致,所以在int在int32或int64之前没有进行类型转换的赋值、比较和数算(参见显示类型转换一节)将被报告为编译时错误。默认情况下,文字量的类型为int。注意:有一些不常见的64位CPU架构使用32位无符号整数作为int类型。Go支持的语言有三种:amd64p32、mips64p32和mips64p32le。第三个特殊的名字是uint。它遵循与int相同的规则,只是它是无符号的(值总是0或正数)。整数还有两个特殊的名字:rune和uintptr。我们之前学过符文文字,我们会在fret字符串和符文类型一节讨论符文类型,在第16章讲uintptr。选择要使用的整数Go中的整数类型比其他一些语言中的多。这么多选择,你可能想什么时候用哪个。有三个简单的原则:如果操作二进制文件格式或网络协议本身是具有特定内存大小或符号的整数,则使用相应的整数。如果库函数被编写成兼容所有整数类型,那么使用泛型参数来表示任意整数(我们将在第五章讨论函数及其参数,在第八章讨论泛型)。在所有其他情况下使用int。注意:你可能会在旧代码中看到一些功能相同的函数,只是一个参数和变量是int64,另一个是uint64。这是因为这些API是在泛型被添加到Go之前编写的。不,我们需要为不同的类型编写名称略有不同的相同算法。使用int64和uint64意味着代码只需要编写一次,调用者可以通过类型转换传递它,并转换返回值。在Go标准库中可以看到很多这种用法,strconv包中有FormatInt/FormatUint和ParseInt/ParseUint。整数运算符Go integer支持常见的算术运算:+、-、*、/和%的余数。如果要获得浮点值,需要使用类型转换将整数转换为浮点值。同时,将整数除以0会导致恐慌(我们将在第9章详细讨论恐慌)。注意:在Go语言中,整数除法遵循向下取值的规则。请参见Go文档中关于算术运算符的部分。可以用=组合任何算术运算符来修改变量:+=、-=、* =、/=和% =。比如执行下面这段代码,x的最终值是20。var x int = 10x *= 2复制代码使用= =,!=、、=、Go中也有整数运算的位运算。可以将整行左右移位,也可以用&(逻辑与)、(逻辑或)、(逻辑异或)和&逻辑与非进行位屏蔽操作。像算术运算符一样,我们可以用=拼接逻辑运算符来修改变量:&=、 =、=、&=、=浮点型Go语言中有两种浮点类型,如下表所示:表2-2 GO语言中的两种浮点类型该名称的最大绝对值是最小(非零)绝对值浮点数(e+)。50600.和integer一样,浮点型的零值也是0。Go语言中的浮点类型类似于其他语言中的浮点类型。Go IEEE 754规范提供了广泛的范围和有限的精度。选择使用哪种浮点类型非常简单:如果不需要与现有格式兼容,就使用float64。literal的默认类型是float64,所以保持float64是最简单的选择。这也有助于消除浮点精度问题,因为float32只有6位或7位十进制精度。除非通过性能测试发现大问题(测试和性能调优将在第15章解释),否则不需要担心内存使用的差异。更大的问题是是否应该使用浮点数。大多数情况下,答案是否定的,和其他语言一样,Go的浮点数范围很广,但它无法存储这个范围内的所有值。它存储最接近的值。因为浮点是不精确的,所以它只能在不精确的值是可接受的或者浮点规则被完全理解的情况下使用。这使它局限于图形和科学计算。警告:浮点数不能准确表示小数。不要在需要钱或其他确切价值的地方使用它。我们将在第10章中学习处理精确十进制值时的第三方模块。IEEE 754如前所述,Go(和大多数其他编程语言)根据IEEE 754规范存储浮点数。具体规则不在本文讨论范围内,不容易理解。例如,如果使用float64存储–3.1415,其在内存中的64位存储显示为:1111复制代码这个值是-3.1。46667很多程序员都知道整数的二进制是什么样子的(最右边的位是1,后面是2,后面是4,依此类推)。浮点数完全不同。在64位中,1位用于表示符号位(正或负),11位用于表示二进制索引(也称为顺序码),52位用于表示归一化格式的数(也称为尾数)。单击此处了解有关IEEE 754的更多信息。除%之外,所有数学和比较运算符都可以用于浮点数。浮点数的除法有一些有趣的性质。将非零浮点变量除以0将返回+Inf或-Inf(正无穷大或负无穷大),具体取决于符号位。而值为0的浮点变量除以0将返回NaN(不是数字)。虽然Go语言允许= =和!=做浮点比较,但不要做。由于浮点数的不精确性,读者认为相等的两个数可能不相等。你要定义一个最大允许误差,然后比较两个浮点的差值是否小于它。该误差(有时称为ε)取决于所需的精度,没有放之四海而皆准的规则。如果读者不清楚,可以向有经验的人求助。如果身边没有这样的人,可以点击这里了解一下(这进一步说明了浮点数应该只在绝对必要的时候使用)。复数类型(不用于高概率)还有一种数字型的,不是很拉风。Go语言提供了对复数的一级支持。如果读者不知道复数是什么,可以直接跳过这一部分。Go语言对复数的支持不多。Go中定义了两个复数类型。Complex64使用float32值来表示实部和虚部,complex128使用float64值。两者都在complex的内置函数中声明。Go通过一些规则确定函数输出的类型:如果在函数参数中使用非类型化常量或文字,将会创建一个默认类型为complex128的非类型化复杂文字。如果传递到complex中的所有值都是float32类型,则创建complex64。如果一个值是float32,另一个值是float32范围内的无类型常量或文字,则创建complex64。此外,创建的所有案例都很复杂128。复数可以使用所有标准的算术运算符。与浮点值一样,您可以使用= =或!=比较复数,但是有一个精度的问题。最好是用误差来对比。复数的实部和虚部可以分别通过内置函数Real和imag提取。math/cmplx包中还有一些函数可用于操作complex128值。复数的两种零值将0赋给实部和虚部。例2-1演示了如何在一个简单的函数中使用复数。读者可以自己在围棋场上跑步。从这里的输出也可以看出浮点是不准确的。如果你想知道5基本型的文字量是多少,Go支持通过虚部文字量来表示复数的虚部。它与浮点文字非常相似,只是在末尾有一个I。虽然内置了复数类型,但在数据科学领域并不流行。主要是因为语言中不支持其他特性(比如矩阵),各种库需要使用低效的替代品,比如切片(我们会在第三章学习切片,第六章学习如何实现切片)。但是如果需要在程序中运算Mandelbrot集合或者实现二次方程,可以使用复数的支持。读者可能想知道为什么Go语言内置复数。答案很简单:Go语言的创始人之一Ken Thompson(他也是Unix的发明者之一)认为它们很有趣(你永远也开不了大玩笑~)。有一些关于在Go的后续版本中删除复数的讨论,但是直接忽略这个特性会很简单。注意:如果想用Go写科学计算应用,可以用第三方的包Gonum。它使用复数,并提供了一个线性代数,矩阵,积分和数据统计库。但建议先考虑其他语言。针串和符文类型接下来是字符串。像大多数现代语言一样,Go有一个内置的字符串类型。字符串的零值是空字符串。支持Unicode:正如我们在字符串文字一节中所展示的,您可以将Unicode字符放入字符串中。类似整数和浮点类型,字符Lu可以用= =进行相等的比较和使用!=进行不相等的比较,或者使用, =,Go中的字符串是不可变的。可以重新分配字符串变量,但不能给它分配字符串本身的值。Go还有一个表示单个代码点的类型。Rune type是int32 type的别名,就像byte是uint8的别名一样。不难猜测,符文文字的默认类型是rune,而字符串文字的默认类型是string。如果是为了字符,请使用符文类型而不是int32。它们在编译器中可能没有什么不同,但是我们应该通过类型来声明代码的意图。var myFirstInitial rune = J ///OK-类型名与用途相匹配。var Mylastinical int 32 = b //不好-合法但令人困惑复制代码在下一章,我们将更详细地讨论字符串,解释它们的实现细节,与字节和符文类型的关联,以及它们的高级特性和缺点。显式类型转换许多编程语言中的数字类型可以根据需要自动相互转换。这称为自动类型提升。虽然看起来很方便,但结果是制定规则合理地将一种类型转换为另一种类型很复杂,而且往往会导致意想不到的后果。Go是一种重视清晰性和可读性的语言,它不允许变量之间的自动类型提升。对于类型不一致的变量,类型转换是必要的。即使是内存大小不同的整数和浮点数,在运算前也必须转换成相同的类型。这样类型就很明确了,不需要记住任何类型转换规则(见例2-2)。实施例2-2var x int = 10变量y浮动64 = 30.2var z float64 = float64(x) + yvar d int = x + int(y)fmt。打印(z,d)复制代码在上面的代码中,我们定义了四个变量。x的类型为int,值为10,y的类型为float64,值为30.2。因为它们不是同一类型,所以在添加之前需要进行转换。对于变量Z,我们使用float64类型转换将X转换为float64,对于变量D,我们使用int类型转换将X转换为int。运行代码,输出结果是40.2 40。这种对类型的严格限制还有其他作用。因为Go中所有的类型转换都是显式的,所以其他的Go类型不能视为布尔类型。在许多编程语言中,非零数字或非空字符串被解释为布尔值true。和自动类型提升一样,不同语言的真值规则不一致也会产生问题。也在意料之中,围棋不会允许这种真值。事实上,其他类型不能隐式或显式地转换为布尔类型。如果要将其他数据类型转换为布尔类型,必须使用比较运算符(= =,!=, ,注意:类型转换是Go中为了简单和清晰而使用空间的地方。这种取舍我们会看到很多次。真正的围棋把容易理解放在简单之上。比较:var =Go作为一种克制语言,有很多声明变量的方式(Rob Pike在一次公开演讲中说过,如果重新设计Go语言,他不会保留那么多声明变量的方式)。原因是每种声明风格都与该风格的使用方式有关。让我们来看看在Go中声明变量的方法,以及它们适用的场景。在Go语言中声明变量的最长方法之一是使用var关键字、显式类型和赋值。:=有限制。如果在包级别声明变量,必须使用var,并且:=不能在函数外部使用。如何决定使用哪种方法?一如既往,选择意图最明确的。声明函数最常见的方式是:=。函数,在声明多个包级变量时使用声明列表。函数中应避免以下情况:=:使用var x int用零值初始化变量。这样会让赋值零值的意图更加清晰。当使用无类型的常量或文字为变量赋值,并且不需要常量或文字的默认类型时,请使用长var形式。虽然可以通过x := byte(20)的类型进行转换,但var x byte = 20是一种更真实的书写方式。因为:=允许给新变量和已有变量赋值,有时候在你认为你会用到已有变量的时候会创建新变量(第四章有详细解释)。在这些场景中,var用于明确声明所有新变量,然后使用赋值操作符(=)为新老变量赋值。尽管var和:=都允许在同一行中声明多个变量,但建议仅在函数或逗号ok语句返回多个值时使用(参见第3章和第5章)。变量要尽量少在函数外声明,这叫做包代码块(见第四章)。修改包级变量不是一种好的做法。当变量在函数之外时,很难跟踪对它所做的更改,这就很难理解程序中的数据流。还可能带来不容易发现的bug。通常,实际上不可变的变量应该只在包代码块中声明。提示:避免在函数之外声明变量,因为这将使数据流变化的分析变得复杂。你可能想知道Go是否提供了保证数据不变性的方法?是的,但它与其他编程语言略有不同。是时候学习const了。使用常量许多语言都有声明不可变值的方法。由Go中的const关键字实现。乍一看,它和其他语言一模一样。请在Go Playground测试示例2-3的代码。运行上述代码将导致编译错误,报告以下错误:。/prog.go:20:2:无法赋值给int64类型的常数10)。/prog.go:21:2:无法赋值给y(无类型的字符串常量“hello复制代码如您所见,我们在包级别和函数内部声明变量。像var一样,您可以(也应该)在括号中声明一组关联的常数。但是注意,Go语言中的const非常有限。Go中的常量用于为文字提供名称。只能存储编译器在编译时可以解析的值。这意味着可以分配以下值:数字文字量真假字符串古代北欧文字内置了函数complex、real、imag、len和cap。由上述值和运算符组成的表达式。注意:我们将在下一篇文章中讨论len和cap。还有一个值可以和const一起使用,那就是iota。我们将在第7章解释我们自己类型的创建时讨论iota。Go没有提供一种方法来指定运行时计算值是不可变的。我们将在下一篇文章中了解到,不存在不可变的数组、切片、字典(映射)或结构,也不可能在结构中声明一个字段是不可变的。在这里看是没有限制的。在函数内部,变量是否被修改是非常清楚的,所有的可变性都不是那么重要。在第五章,我们将学习Go如何防止传递给函数的参数被修改。提示:Go中的常量是为文字量提供名称的一种方式。在Go中不能将变量声明为不可变的。类型化和非类型化常量常量可以是类型化的,也可以是非类型化的。没有一个类型像literal一样,没有自己的类型,在无法推断其他类型时有一个默认类型。类型化变量只能赋给该类型的变量。常数是否有类型取决于它被声明的原因。如果给定数学常数的一个名称用于多个数值类型,它应该保持非类型化。通常,保持常量无类型化更灵活。在某些情况下,您可能希望向常数添加类型。在第7章中,通过iota创建枚举时将使用类型化常量。没有类型的常数声明如下:常数x = 10复制代码以下声明是合法的:var y int = xvar z float64 = x变量d字节= x复制代码具有类型常数的声明如下:const typedX int = 10复制代码该常量只能赋给int类型的变量。将它赋给另一种类型将会报告一个编译时错误:不能在赋值中将typedX(int类型)用作float64类型复制代码未使用的变量Go的一个目标是让大型团队的编程辅助变得更容易。为此,围棋制定了一些独特的规则。在《云原生系列-Go环境配置》的Go语言章节中,我们了解到Go程序需要通过go fmt进行格式化,这样更容易编写代码操作工具,提供代码规范。Go的另一个要求是需要读取每个局部变量。声明一个局部变量但不读取它会报告一个编译时错误。编译变量的未使用检测并不极端。只要变量被读取过一次,编译器就不会报告错误,即使写入的变量从未被再次读取过。以下有效代码可以在Go游乐场运行:func main() {X := 10 //这个被分配给readx = 20fmt。打印目录(x)X = 30 //本文分配给读者}复制代码虽然编译器和go vet不能捕捉到未使用的10和30对x的赋值,但是有一些第三方工具可以做到这一点。这些工具将在第11章中讨论。注意:Go编译器不能阻止你创建未读的包级变量。这是避免创建包级变量的另一个原因。未使用的常数也许出乎意料的是,Go编译器允许我们通过const创建未读常量。这是因为Go语言中的常数是在编译时计算的,不会产生负面影响。也很容易删除。如果常量没有被使用,你就不需要在编译后的二进制文件中包含它。命名变量和常数Go中的变量命名规则与Go开发者为命名变量和常量所遵循的规范并不相同。像大多数语言一样,Go需要一个标识名和一个字母或下划线的开头。该名称可以包含数字、下划线和字母。Go对字母和数字的定义比其他语言更宽泛。支持可视为字母或数字的Unicode字符。因此,例2-4中的变量定义在Go中完全有效。示例2-4不应使用的变量名_0 := 0_0_ := 20π := 3a := hello // Unicode U+FF41fmt。Println(_0)fmt。Println(_)fmt。Println(π)fmt。印刷品(a)复制代码虽然可以用上面的代码,但是请不要用这样的变量来命名。这些名称不可信的原因是它们打破了熟悉的代码函数的基本规则。这些名字不容易理解或在键盘上输入。相似Unicode危害最大,因为虽然看起来是同一个字符,但却是完全不同的变量。你可以在Go Playground运行例2-5的代码。示例2-5具有相似代码点的变量名func main() {a := hello // Unicode U+FF41A := goodbye //标准小写字母a (Unicode U+0061)fmt。印刷品(a)fmt。印刷品(a)}复制代码运行该程序获得的结果如下:你好再见复制代码虽然下划线可以用于变量名,但很少使用,因为authentic Go不使用蛇形命名(如index_counter或number_tries)。相反,当出现多个单词时,使用驼峰名称(indexCounter或numberTries)。注意:下划线本身(_)是Go中一个特殊的标识符名称。我们将在第5章解释函数时讨论它。在很多编程语言中,常量都是用大写字母表示,单词之间用下划线分隔(比如INDEX_COUNTER或者NUMBER_TRIES)。Go不遵循这个规范。这是因为Go依赖于包级声明的第一个字母来确定是否可以在包外访问它。我们会在第10章讲包的时候再回到这个知识点。函数中使用了更多的短变量名。变量的范围越小,使用的名称就越短。Go单字母变量非常常见。例如,在for-range循环中使用K和V(键和值的缩写)作为变量名。如果使用标准的for循环,I和J通常用作索引变量名。还有其他一些命名通用类型变量的隧道方法,我们在讨论标准库时会不断提到。一些编程语言使用弱类型系统,这鼓励开发人员在变量名中包含类型名。Go是一种强类型语言,所以不需要像这样记录变量类型。但是对于变量类型和单字母名称有一些规范。人们会用类型的第一个字母作为变量名(比如I代表整数,F代表浮点,B代表布尔)。在定义自己的类型时,规范是类似的。这些简称有两个目的。首先,它们消除了重复的类型名,使代码更短。第二是它用于检测代码的复杂性。如果你发现你搞不清楚简称变量是什么,很可能是代码块太长了。在包级别命名变量和常量时,使用更具描述性的名称。名称应该仍然不包含类型,但是由于它的范围更广,所以有必要使用更完整的名称来清楚地反映它所代表的值。总结这篇文章解释了很多,我们知道如何使用内置类型,声明变量,使用赋值语句和运算符。

免责声明:本站所有信息均搜集自互联网,并不代表本站观点,本站不对其真实合法性负责。如有信息侵犯了您的权益,请告知,本站将立刻处理。联系QQ:1640731186