前言
rust没咋整明白,再来了解下go语言基础知识,参考资料为菜鸟教程以及go程序设计语言。go语言与google关系匪浅,且发明人之一还是c语言的发明人之一,可以说是很神奇了。
构建系统
go和cargo的编译命令挺像,也有build和run
编码风格
关于函数大括号,go似乎更严格,虽然rust有标准风格,但括号不在同一行也可以编译通过,而go会直接报错:
~/project/hello_go$ go build hello.go
# command-line-arguments
./hello.go:6:1: syntax error: unexpected semicolon or newline before {
go也有gofmt可以格式化代码。
与python一样,一行代表一个语句结束,如果想在一行写多个语句,可以使用;分隔。
注释与c相同,使用//和/**/。
go语言中标识符的开头字母的大小写决定了这个符号是否是外部符号,大写可以被其他人所用,否则只能在包内部可见并可用。
与python一样,go支持字符串通过+连接。
数据类型
布尔
数字
和rust类似,以占用空间大小命名类型,包括各种有符号无符号的整型,浮点型,另外还有byte,rune,uint,int与uintptr等类型。
字符串
派生类型
指针
go中的指针与c中的也很像
数组
形式如下:
var variable_name [SIZE] variable_type
go中的数组与c中的很像,只是语法不同。
结构体
同上,和c很像
Channel类型
函数
切片
声明形式:
//声明一个未指定大小的数组来定义切片:切片不需要说明长度。
var identifier []type
//或使用 make() 函数来创建切片:
var slice1 []type = make([]type, len)
//也可以简写为
slice1 := make([]type, len)
//也可以指定容量,其中 capacity 为可选参数。
make([]T, length, capacity)
需要注意的是不要和长度不确定的数组的定义混了,长度不定数组定义实例:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
切片有点像可变长数组
接口类型
形式:
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 定义结构体 */
type struct_name struct {
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/
}
实例:
package main
import (
"fmt"
)
type Phone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
fmt.Println("I am iPhone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
Map类型
map的定义同样使用make:
/* 使用 make 函数 */
map_variable := make(map[KeyType]ValueType, initialCapacity)
类型转换
形式:
type_name(expression)
实例:
var a int = 10
var b float64 = float64(a)
变量
go是强类型语言。
变量声明
第一种,指定变量类型,如果没有初始化,则变量默认为零值。
形式如下:
var v_name v_type
v_name = value
第二种,根据值自行判定变量类型。
形式如下:
var v_name = value
第三种,如果变量已经使用 var 声明过了,再使用 := 声明变量,就产生编译错误,格式:
v_name := value
intVal := 1 相等于:
var intVal int
intVal =1
这也就是说go中不能二次声明。
多变量声明
形式如下:
//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断
vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
a, b, c := 5, 7, "abc"
// 这种因式分解关键字的写法一般用于声明全局变量
var (
vname1 v_type1
vname2 v_type2
)
交换变量值
a, b = b, a
作用域
基本与c相同,局部变量,全局变量等
常量
定义实例如下:
const b string = "abc"//显式类型定义
const b = "abc"//隐式类型定义
用做枚举:
const (
Unknown = 0
Female = 1
Male = 2
)
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
iota 可以被用作枚举值:
const (
a = iota
b = iota
c = iota
)
简写如下:
const (
a = iota
b
c
)
不要把这个和itoa混了。
Range
与python中的range可以产生序列不同,go中的range用于迭代遍历成员。
运算符
运算符和c基本一致
控制流
分支
if
else if
else
switch
select
循环
for
函数
定义形式:
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
}
函数可以返回多个值
值传递和引用传递
和c类似,传引用是通过指针实现的。
函数作为实参
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 getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
func main(){
/* nextNumber 为一个函数,函数 i 为 0 */
nextNumber := getSequence()
/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
/* 创建新的函数 nextNumber1,并查看结果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}
方法
形式如下:
func (variable_name variable_data_type) function_name() [return_type]{
/* 函数体*/
}
实例:
package main
import (
"fmt"
)
/* 定义结构体 */
type Circle struct {
radius float64
}
func main() {
var c1 Circle
c1.radius = 10.00
fmt.Println("圆的面积 = ", c1.getArea())
}
//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
//c.radius 即为 Circle 类型对象中的属性
return 3.14 * c.radius * c.radius
}
错误处理
实例:
package main
import (
"fmt"
)
// 定义一个 DivideError 结构
type DivideError struct {
dividee int
divider int
}
// 实现 `error` 接口
func (de *DivideError) Error() string {
strFormat := `
Cannot proceed, the divider is zero.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)
}
// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// 正常情况
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// 当除数为零的时候会返回错误信息
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg is: ", errorMsg)
}
}
并发
协程
形式:
go 函数名( 参数列表 )
实例:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
通道
创建通道形式如下:文章来源:https://www.toymoban.com/news/detail-501618.html
ch := make(chan int)
实例:文章来源地址https://www.toymoban.com/news/detail-501618.html
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 把 sum 发送到通道 c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从通道 c 中接收
fmt.Println(x, y, x+y)
}
到了这里,关于go语言学习_incomplete的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!