对标 C + Python,明早我要会看 go 代码
Posted 看,未来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对标 C + Python,明早我要会看 go 代码相关的知识,希望对你有一定的参考价值。
文章目录
记得上次这么豪横,还是在上次,对标 Python 上手 lua 的时候。
时间紧迫,这篇我就按照我能看懂的标准来了。
安装 go 环境,你好 world
官网下载,我用 Linux amd 那个版本的。一百多兆,自己估计一下网速。
直接解压到 /usr/local 目录下:
tar -C /usr/local -xzf goXXXXX.tar.gz
添加到环境变量:
export PATH=$PATH:/usr/local/go/bin
source /etc/profile
问候世界脚本:
package main
import "fmt"
func main()
fmt.Println("Hello, World!")
运行脚本:
go run hello.go
或者你想编译一下再运行也行:
go build hello.go
./hello
这点和 lua 倒是有点像。
代码讲解
麻雀虽小,五脏俱全。不要小看那一小段代码。
package main //定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包
//每个 Go 应用程序都包含一个名为 main 的包。
import "fmt" //导入 fmt 包
/*
程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,
一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
*/
func main()
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!") //输出函数
/*
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,那么使用这种形式的标识符的对象就可以被外部包的代码所使用
(客户端程序需要先导入这个包),这被称为导出;
标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的。
*/
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。
标识符
人家管变量名叫标识符,那咱就入乡随俗。
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(AZ和az)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
跟 C 语言一样的。这里我为什么要对标 C 语言?因为这两种语言的诞生都离不开同一个人。那为什么我要再说对标 Python 语言?前面都看到了,go 里面有 Python 的优势:轻便,包。因为 go 是晚于 C 语言诞生的,所以可以说它集二者之大成也不为过。
这里顺便提一下,go 里面拼接字符串和 Python 里面一样,不像 C 语言那么繁琐。
关键字 和 预定义标识符
这不用去记,按我的方法来起名字(凡是起名必带 _)是不可能和这些关键字冲突的。
基本数据类型
0)变量声明
var 变量名字 类型 = 表达式
例:
var num int = 10
其中“类型”或“= 表达式”两个部分可以省略其中的一个。
1)根据初始化表达式来推导类型信息
2)默认值初始化为0。
例:
var num int // var num int = 0
var num = 10 // var num int = 10
1)整型
1.1)整型类型
rune 类型是 Unicode 字符类型,和 int32 类型等价,通常用于表示一个 Unicode 码点。rune 和 int32 可以互换使用。
byte 是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是 一个小的整数。
uintptr 是一种无符号的整数类型,没有指定具体的bit大小但是足以容纳指针。 uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。
不管它们的具体大小,int、uint和uintptr是不同类型的兄弟类型。其中int和int32也是 不同的类型, 即使int的大小也是32bit,在需要将int当作int32类型的地方需要一个显式 的类型转换操作,反之亦然。
有符号整数采用 2 的补码形式表示,也就是最高 bit 位用作表示符号位,一个 n bit 的有 符号数的值域是从 -2^n-1 到 2^n-1−1
。例如,int8类型整数的值域是从-128 到 127, 而uint8类型整数的值域是从0到255。
1.2)整型运算
二元运算符:算术运算、逻辑运算和比较运算,运算符优先级从上到下递减顺序排列
在同一个优先级,使用左优先结合规则,但是使用括号可以明确优先顺序。
算术运算符+、-、*和/可以适用与于整数、浮点数和复数,但是取模运算符%仅用于整数间的运算。 % 取模运算符的符号和被取模数的符号总是一致的。除法运算符 / 的行为则依赖于操作数是否 全为整数,比如5.0/4.0的结果是1.25,但是5/4的结果是1,因为整数除法会向着0方向截断余数。
两个相同的类型可以使用下面的二元比较运算符进行比较;比较表达式的结果是布尔类型。
位操作运算符:
注意 位操作运算符 ^ 作为二元运算符时是按位异或(XOR),当用作一元运算符时表示按位取反。
许多整形数之 间的相互转换并不会改变数值;它们只是告诉编译器如何解释这个值。但是对于将一个大尺寸的整数类 型转为一个小尺寸的整数类型,或者是将一个浮点数转为整数,可能会改变数值或丢失精度。 浮点数到整数的转换将丢失任何小数部分,然后向数轴零方向截断。
1.3)浮点数
Go语言提供了两种精度的浮点数,float32和float64。它们的算术规范由IEEE754浮点数国际标准定义, 该浮点数规范被所有现代的CPU支持。
一个float32类型的浮点数可以提供大约6个十进制数的精度,而float64则可以提供约15个十进制数的精度。
函数math.IsNaN用于测试一个数是否是非数NaN,math.NaN则返回非数对应的值。虽然可以用math.NaN来 表示一个非法的结果,但是测试一个结果是否是非数NaN则是充满风险的,因为NaN和任何数都是不相等的。 如果一个函数返回的浮点数结果可能失败,最好的做法是用单独的标志报告失败。
nan := math.NaN()
fmt.Println(nan == nan, nan < nan, nan > nan) // "false false false"
1.4)复数
Go语言提供了两种精度的复数类型:complex64和complex128,分别对应float32和float64两种浮点数精度。内置的complex函数用于构建复数,内建的real和imag函数分别返回复数的实部和虚部。
z := x + yi
x = real(z)
y = imag(z)
复数也可以用==和!=进行相等比较。只有两个复数的实部和虚部都相等的时候它们才是相等的。 math/cmplx包提供了复数处理的许多函数,例如求复数的平方根函数和求幂函数。
1.5)布尔型
布尔值并不会隐式转换为数字值0或1,反之亦然。必须使用一个显式的if语句辅助转换。
1.6)字符串
一个字符串是一个不可改变的字节序列。字符串可以包含任意的数据,包括byte值0,但是通常是用来包含人类可读的文本。文本字符串通常被解释为采用UTF8编码的Unicode码点(rune)序列。
内置的len函数可以返回一个字符串中的字节数目(不是rune字符数目),索引操作s[i]返回第i个字节的字节值,i 必须满足0 <= i < len(s)条件约束。如果试图访问超出字符串索引范围的字节将会导致panic异常。
第 i 个字节并不一定是字符串的第 i 个字符,因为对于非 ASCII 字符的 UTF8 编码会要两个或多个字节。
子字符串操作 s[i:j] 基于原始的 s 字符串的第 i 个字节开始到第 j 个字节(并不包含 j 本身)生成一个新字符串。生成的新字符串将包含 j-i 个字节。不管 i 还是 j 都可能被忽略,当它们被忽略时将采用 0 作为开始位置,采用 len(s) 作为结束的位置。
其中 + 操作符将两个字符串链接构造一个新字符串。
字符串可以用 == 和 < 进行比较;比较通过逐个字节比较完成的,因此比较的结果是字符串自然编码的顺 序。
字符串值也可以用字符串面值方式编写,只要将一系列字节序列包含在双引号即可。
字符串的值是不可变的:一个字符串包含的字节序列永远不会被改变,当然我们也可以给一个字符串变量分配一个新字符串值。
s := "left foot"
t := s
s += ", right foot"
这并不会导致原始的字符串值被改变,但是变量s将因为+=语句持有一个新的字符串值,但是t依然是包含原先的字符串值。
在一个双引号包含的字符串面值中,可以用以反斜杠\\开头的转义序列插入任意的数据。
字符串和数字的转换
除了字符串、字符、字节之间的转换,字符串和数值之间的转换也比较常见。由strconv包提供这类转换功能。
几个常用函数:
常量
常量表达式的值在编译期计算,而不是在运行期。每种常量的潜在类型都是基础类型:boolean、string 或数字。 一个常量的声明语句定义了常量的名字,和变量的声明语法类似,常量的值不可修改,这样可以防止在运行期被意外或恶意的修改。
和变量声明一样,可以批量声明多个常量;这比较适合声明一组相关的常量:
const (
e = 2.71828182845904523536028747135266249775724709369995957496696763
pi = 3.14159265358979323846264338327950288419716939937510582097494459
)
常量间的所有算术运算、逻辑运算和比较运算的结果也是常量,对常量的类型转换操作或以下函数调用 都是返回常量结果:len、cap、real、imag、complex和unsafe.Sizeof。
iota 常量生成器
iota常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都 写一遍初始化表达式。在一个const声明语句中,在第一个声明的常量所在的行,iota将会被置为0,然 后在每一个有常量声明的行加一。
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
或者下面的例子:
type Flags uint
const (
FlagUp Flags = 1 << iota // is up
FlagBroadcast // supports broadcast access capability
FlagLoopback // is a loopback interface
FlagPointToPoint // belongs to a point-to-point link
FlagMulticast // supports multicast access capability
)
随着iota的递增,每个常量对应表达式1 << iota,是连续的2的幂,分别对应一个bit位置。
无类型常量
许多常量并没有一个明确的基础类型。编译器为这些没有明确的基础类型的数字常量提供比基础类型更高精度的算术运算;你可以认为至少有256bit的运算精度。这里有六种未明确类型的常量类型,分别是无类型的布尔型、无类型的整数、无类型的字符、无类型的浮点数、无类型的复数、无类型的字符串。
通过延迟明确常量的具体类型,无类型的常量不仅可以提供更高的运算精度,而且可以直接用于更多的 表达式而不需要显式的类型转换。
只有常量可以是无类型的。当一个无类型的常量被赋值给一个变量的时候,或者是语句中右边表达式含有明确类型的值,如果转换合法的话,无类型的常量将会被隐式转换为对应的类型。
无论是隐式或显式转换,将一种类型转换为另一种类型都要求目标可以表示原始值。对于浮点数和复数,可能会有舍入处理。
对于一个没有显式类型的变量声明语法(包括短变量声明语法),无类型的常量会被隐式转为默认的变量类型。
注意默认类型是规则的:无类型的整数常量默认转换为int,对应不确定的内存大小,但是浮点数和复数常量则默认转换为float64和complex128。Go语言本身并没有不确定内存大小的浮点数和复数类型,而且如果不知道浮点数类型的话将很难写出正确的数值算法。
如果要给变量一个不同的类型,我们必须显式地将无类型的常量转化为所需的类型,或给声明的变量指 定明确的类型。
变量
声明变量的一般形式是使用 var 关键字:
var identifier type
可以一次声明多个变量:
var identifier1, identifier2 type
指定变量类型,如果没有初始化,则变量默认为零值:
// 声明一个变量并初始化
var a = "RUNOOB"
fmt.Println(a)
// 没有初始化就为零值
var b int
fmt.Println(b)
可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上 var 关键字其实是显得有些多余了,因此我们可以将它们简写为 a := 50 或 b := false。
如果变量已经使用 var 声明过了,再使用 := 声明变量,就产生编译错误。
if 布尔表达式
/* 在布尔表达式为 true 时执行 */
else
/* 在布尔表达式为 false 时执行 */
switch var1
case val1:
...
case val2:
...
default:
...
select
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 你可以定义任意数量的 case */
default : /* 可选 */
statement(s);
循环
和 C 语言的 for 一样:
for init; condition; post
和 C 的 while 一样:
for condition
和 C 的 for(;😉 一样:
for
break、continue、goto 依旧是有的。
函数
func function_name( [parameter list] ) [return_types]
函数体
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int
/* 声明局部变量 */
var result int
if (num1 > num2)
result = num1
else
result = num2
return result
package main
import "fmt"
func main()
/* 定义局部变量 */
var a int = 100
var b int = 200
var ret int
/* 调用函数并返回最大值 */
ret = max(a, b)
fmt.Printf( "最大值是 : %d\\n", ret )
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int
/* 定义局部变量 */
var result int
if (num1 > num2)
result = num1
else
result = num2
return result
package main
import "fmt"
func swap(x, y string) (string, string)
return y, x
func main()
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
引用传递
/* 定义交换值函数*/
func swap(x *int, y *int)
var temp int
temp = *x /* 保持 x 地址上的值 */
*x = *y /* 将 y 值赋给 x */
*y = temp /* 将 temp 值赋给 y */
package main
import "fmt"
func main()
/* 定义局部变量 */
var a int = 100
var b int= 200
fmt.Printf("交换前,a 的值 : %d\\n", a )
fmt.Printf("交换前,b 的值 : %d\\n", b )
/* 调用 swap() 函数
* &a 指向 a 指针,a 变量的地址
* &b 指向 b 指针,b 变量的地址
*/
swap(&a, &b)
fmt.Printf("交换后,a 的值 : %d\\n", a )
fmt.Printf("交换后,b 的值 : %d\\n", b )
func swap(x *int, y *int)
var temp int
temp = *x /* 保存 x 地址上的值 */
*x = *y /* 将 y 值赋给 x */
*y = temp /* 将 temp 值赋给 y */
函数指针
package main
import (
"fmt"
"math"
)
func main()
/* 声明函数变量 */
getSquareRoot := func(x float64) float64
return math.Sqrt(x)
/* 使用函数 */
fmt.Println(getSquareRoot(9))
变量作用域
局部变量
package main
import "fmt"
func main()
/* 声明局部变量 */
var a, b, c int
/* 初始化参数 */
a = 10
b = 20
c = a + b
fmt.Printf ("结果: a = %d, b = %d and c = %d\\n", a, b, c)
全局变量
package main
import "fmt"
/* 声明全局变量 */
var g int
func main()
/* 声明局部变量 */
var a, b int
/* 初始化参数 */
a = 10
b = 20
g = a + b
fmt.Printf("结果: a = %d, b = %d and g = %d\\n", a, b, g)
Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。
数组
声明
var variable_name [SIZE] variable_type
初始化
初始化数组中 中的元素个数不能大于 [] 中的数字。
var balance = [5]float321000.0, 2.0, 3.4, 7.0, 50.0
balance := [5]float321:2.0,3:7.0 // 将索引为 1 和 3 的元素初始化
如果数组长度不确定,可以使用 … 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
var balance = [...]float321000.0, 2.0, 3.4, 7.0, 50.0
或
balance := [...]float321000.0, 2.0, 3.4, 7.0, 50.0
访问数组元素
var salary float32 = balance[9]
小总结
package main
import "fmt"
func main()
var i,j,k int
// 声明数组的同时快速初始化数组
balance := [5]float321000.0, 2.0, 3.4, 7.0, 50.0
/* 输出数组元素 */ ...
for i = 0; i < 5; i++
fmt.Printf("balance[%d] = %f\\n", i, balance[i] )
balance2 := [...]float321000.0, 2.0, 3.4, 7.0, 50.0
/* 输出每个数组元素的值 */
for j = 0; j < 5; j++
fmt.Printf("balance2[%d] = %f\\n", j, balance2[j] )
// 将索引为 1 和 3 的元素初始化
balance3 := [5]float321:2.0,3:7.0
for k = 0; k < 5; k++
fmt.Printf("balance3[%d] = %f\\n", k, balance3[k] )
指针
var var_name *var-type
package main
import "fmt"
func main()
var a int= 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */
ip = &a /* 指针变量的存储地址 */
fmt.Printf("a 变量的地址是: %x\\n", &a )
/* 指针变量的存储地址 */
fmt.Printf("ip 变量储存的指针地址: %x\\n", ip )
/* 使用指针访问值 */
fmt.Printf("*ip 变量的值: %d\\n", *ip )
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
结构体
type struct_variable_type struct
member definition
member definition
...
member definition
一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:
variable_name := structure_variable_type value1, value2...valuen
或
variable_name := structure_variable_type key1: value1, key2: value2..., keyn: valuen
package main
import "fmt"
type Books struct
title string
author string
subject string
book_id int
func main()
// 创建一个新的结构体
fmt.Println(Books"Go 语言", "www.runoob.com", "Go 语言教程", 6495407)
// 也可以使用 key => value 格式
fmt.Println(Bookstitle: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407)
// 忽略的字段为 0 或 空
fmt.Println(Bookstitle: "Go 语言", author: "www.runoob.com")
访问结构体成员
如果要访问结构体成员,需要使用点号 . 操作符,格式为:
结构体.成员名
package main
import "fmt"
type Books struct
title string
author string
subject string
book_id int
func main()
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "www.runoob.com"
Book2.subject = "Python 语言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
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)
/* 打印 Book2 信息 */
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)
结构体作为函数参数
package main
import "fmt"
type Books struct
title string
author string
subject string
book_id int
func main()
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1代写编程代写机器学习模型代写AI python
开源 | 为Go语言设计的机器学习库Gorgonia:对标TensorFlow与Theano
记录一个问题go get -u github.com/go-redis/redis出现错误" invalid character '.' after top-level (代
代写C, C++ or Python 作业,Linux environment下编程代写C, C++ or Python 作业代写