第一个go程序
package main //package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
import "fmt" //基本函数包
func main() { // notice { 不能在单独的行上
fmt.Println("Hello," + " World!")
//1当两语句不在一行时 不需要行分隔符;
//2go语言连接符为+
//3、go的调用方式也类似java 类的写法
}
运行和编译
方法1:编译二进制文件执行
$ go build hello.go //命令行
$ ./hello //命令行
Hello, World! //结果
方法2:
$ go run hello.go
第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
下一行 import “fmt” 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。
变量类型和申明
var identifier type 如:var a int
var b, c int = 1, 2
也可自动判断类型 var v_name = value
var d = true
还可以使用:=
i := 1
多变量申明
如:vname1, vname2, vname3 := v1, v2, v3//可套用上面其他两种方法,用
,`分开即可
默认值
- 数值类型(包括complex64/128)为 0
- 布尔类型为 false
- 字符串为 “”(空字符串)
以下几种类型为 nil:
var a *int
var a []int
var a map[string] int
var a chan int
var a func(string) int
var a error // error 是接口
值类型和引用类型
所有像 int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值:
数值类型的=是拷贝,引用类型的=是地址被复制
你可以通过 &i 来获取变量 i 的内存地址
局部变量一旦申明必须被使用
如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,例如下面这个例子当中的变量 a:
func main() {
var a string = “abc”
fmt.Println(“hello, world”)
}
但是可以在全局变量中使用它
交换变量与_
如果你想要交换两个变量的值,则可以简单地使用 a, b = b, a,两个变量的类型必须是相同。
空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。
常量申明
显式类型定义: const b string = “abc”
隐式类型定义: const b = “abc”
iota
第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
类型转换
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
条件判断
Go 没有三目运算符,所以不支持 ?: 形式的条件判断。
select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
if
if语句,如
if a < 20 {
xxx
}
for
和 C 语言的 for 一样:
for init; condition; post { } //初值;循环控制条件;赋值增量或减量
和 C 的 while 一样:
for condition { }
和 C 的 for(;;)
一样:
for { }
init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。
range
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap {
newMap[key] = value
}
这个没php的foreach简洁==
函数
go语言至少需要一个main函数
func function_name( [parameter list] ) [return_types] {
函数体
}
//如
func max(num1, num2 int) int {
}
func main() {
var a int = 100
var b int = 200
var ret int
/* 调用函数并返回最大值 */
ret = max(a, b)
fmt.Printf( "最大值是 : %d\n", ret )
}
函数返回多个值
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob") //这里也能自动推断
fmt.Println(a, b)
}
函数作为参数
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 { //后面的func() int 当成一体的 就是一个返回值!
i:=0
return func() int { //实际上就是把这里原封不动抄上去了而已
i+=1
return i
}
}
func main(){
/* nextNumber 为一个函数,函数 i 为 0 */
nextNumber := getSequence()
/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
fmt.Println(nextNumber())//1
fmt.Println(nextNumber())//2
fmt.Println(nextNumber())//3
/* 创建新的函数 nextNumber1,并查看结果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())//1
fmt.Println(nextNumber1())//2
}
go方法
https://www.runoob.com/go/go-method.html
数组
其实记住这2种就够了
var balance [10] float32 //仅仅申明 后续可以用 balance[1]=1 来赋值
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} //三个点也可换成数组 手动指定长度
申明数组,如
var balance [10] float32
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
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 := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
如果设置了数组的长度,我们还可以通过指定下标来初始化元素:
// 将索引为 0 和 2 的元素初始化
balance := [5]float32{0:2.0,2:7.0}
语言切片(动态数组)
Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
[]
方法 :len、cap等
指针
var a int= 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */
ip = &a /* 指针变量的存储地址 */
fmt.Printf("*ip 变量的值: %d\n", *ip )/* 在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。 */
当一个指针被定义后没有分配到任何变量时,它的值为 nil。nil 指针也称为空指针。
一个指针变量通常缩写为 ptr。
var ptr *int
fmt.Printf("ptr 的值为 : %x\n", ptr )//这里输出的是0!
指向指针的指针
package main
import "fmt"
func main() {
var a int
var ptr *int
var pptr **int
a = 3000
/* 指针 ptr 地址 */
ptr = &a
/* 指向指针 ptr 地址 */
pptr = &ptr
/* 获取 pptr 的值 */
fmt.Printf("变量 a = %d\n", a )
fmt.Printf("指针变量 *ptr = %d\n", *ptr )
fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
}
函数参数指针
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int= 200
swap(&a, &b);
}
func swap(x *int, y *int) {
var temp int
temp = *x /* 保存 x 地址的值 */
*x = *y /* 将 y 赋值给 x */
*y = temp /* 将 temp 赋值给 y */
}
结构体—对象 更准确的说是js那种对象 没有方法的数组对象
package main
import "fmt"
//这里的type是定义基础类型的意思 是为了后面用var Book1 Books 这种语法
type Books struct { //其实和变量的声明一样 type类似func var 后面是名字 在后面是类型
title string
author string
subject string
book_id int
}
func main() {
// 创建一个新的结构体
fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
// 也可以使用 key => value 格式
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
// 忽略的字段为 0 或 空
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
}
{Go 语言 www.runoob.com Go 语言教程 6495407}
{Go 语言 www.runoob.com Go 语言教程 6495407}
{Go 语言 www.runoob.com 0}
也可用点的形式
func main() {
var Book1 Books //这里是var了!
var Book2 Books
/* book 1 描述 */
Book1.title = "Go 语言"
语言切片—动态数组
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
//你可以声明一个未指定大小的数组来定义切片:
var identifier []type //!这里和普通数组那里的区别是,这里方括号李既没数字也没三个点!
//也可指定切片的length和容量
var slice1 []type = make([]T, length, capacity) //length 必须写 初始切片的长度 capacity可选 代表最大的length
// 如
var numbers = make([]int,3,5) //定义
len和cap函数
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)
}
切片截取 用到的时候看https://www.w3cschool.cn/go/go-slice.html
语言范围 Range ----实际上是foreach
看之前for循环那就行 第一个是索引 第二个是值
Map集合
法一 用切片的形式
var countryCapitalMap map[string]string /*创建集合 */
countryCapitalMap = make(map[string]string) //这个看的我有点懵 以后再查把
/* map插入key - value对,各个国家对应的首都 */
countryCapitalMap [ "France" ] = "巴黎"
countryCapitalMap [ "Italy" ] = "罗马"
countryCapitalMap [ "Japan" ] = "东京"
countryCapitalMap [ "India " ] = "新德里"
/*使用键输出地图值 */
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [country])
}
法二
countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}
delete
delete(countryCapitalMap,"France");
接口
type Phone interface {
call()
}
type NokiaPhone struct {
}
//func max(num1, num2 int) int 之前的函数定义是这样 这里把名字后置了 就变成了接口
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()
}
错误处理
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。
error类型是一个接口类型,这是它的定义:
type error interface {
Error() string
}
我们可以在编码中通过实现 error 接口类型来生成错误信息。
函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现
}
并发
其实很简单 用go前缀开启即可
https://www.runoob.com/go/go-concurrent.html
用到看这里