go快速入门 1
go开发目录
个人
团队
go关键词
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
语言组成
包声明
package main
第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
引入包
import “fmt”
告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
函数
func main(){
fmt.Println(“hello world! go and golang”);
}
是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
变量
var name string = “go”
go的变量声明会采用var关键词进行声明同时会携带上声明的数据类型
go保留字
常量: true false iota nil
类型: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
=bool byte rune string error
方法: make len cap new append copy close delete
complex real imag
panic recover
基本数据类型
类型 | 描述 |
---|---|
uint | 32位或64位 |
uint8 | 无符号 8 位整型 (0 到 255) |
uint16 | 无符号 16 位整型 (0 到 65535) |
uint32 | 无符号 32 位整型 (0 到 4294967295) |
uint64 | 无符号 64 位整型 (0 到 18446744073709551615) |
int | 32位或64位 |
int8 | 有符号 8 位整型 (-128 到 127) |
int16 | 有符号 16 位整型 (-32768 到 32767) |
int32 | 有符号 32 位整型 (-2147483648 到 2147483647) |
int64 | 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
byte | uint8的别名(type byte = uint8) |
rune | int32的别名(type rune = int32),表示一个unicode码 |
uintptr | 无符号整型,用于存放一个指针是一种无符号的整数类型,没有指定具体的bit大小但是足以容纳指针。 |
uintptr | 类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。 |
float32 | IEEE-754 32位浮点型数 |
float64 | IEEE-754 64位浮点型数 |
complex64 | 32 位实数和虚数 |
complex128 | 64 位实数和虚数 |
详细说明:https://www.cnblogs.com/itbsl/p/9854681.html
建议先去看看再回来继续。
类型定义
package main
import "fmt"
type ih interface { // 定义接口
}
type user struct { // 定义结构体属性
name string // 结构体属性
age int
}
func (u user) getAge() int { //getAge方法名 int 返回参数类型 要先定义结构体
return u.age
}
func main() {
//创建结构体
//实例化
tu := user{
name: "哈哈a",
age: 12,
}
fmt.Println(tu.name)
fmt.Println(tu.getAge()) //调用
}
作用域
go语言声明
有四种主要声明方式:
var(声明变量), const(声明常量), type(声明类型), func(声明函数)。
变量var
语法
// 变量
var 变量名 变量类型
var (
a int
b int
)
例子
// 正常定义方式
var a int = 0
fmt.Println("常定义方式 :", a)
// 根据值得知类型
var c = 0
fmt.Println("根据值得知类型 :", c)
// := 定义方式
b := 0
fmt.Println(" := 定义方式 :", b)
// 批量定义
var (
v_a int = 201
v_b int
)
v_b = 202
fmt.Printf("批量声明变量 v_a:%a | v_b:%b \n", v_a, v_b)
常量 const
语法
const identifier [type] = value
const (
n1 = iota //0
n2 //1
n3 //2
n4 //3
)
const c_name1, c_name2 = value1, value2
例子
const GNAME = "sixstar"
const (
a = 1
b = 2
)
const (
a1 = 10
b1
c1
)
fmt.Println("GNAME", GNAME)
fmt.Println("a, b: ", a, b)
fmt.Println("a1, b1, c1: ", a1, b1, c1)
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota是go语言的常量计数器,只能在常量的表达式中使用。 iota在const关键字出现时将被重置为0。const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。 使用iota能简化定义,在定义枚举时很有用
const (
a1 = iota
b1
c1
)
const (
a1 = iota
b1 = iota
c1 = iota
)
fmt.Println("a1, b1, c1: ", a1, b1, c1)
// 输出都是 : a1, b1, c1: 0 1 2
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)
// 输出是 :0 1 2 ha ha 100 100 7 8
const (
a, d = iota + 1, iota + 10
b, e
c, f
)
fmt.Println(a, b, c, d, e, f)
// 输出是 :1 2 3 10 11 12
函数 func
特点
------无需声明原型。
------支持不定变参。
------支持多返回值。
------支持命名返回参数。
------支持匿名函数和闭包。
------函数也是一种类型,一个函数可以赋值给变量。
------不支持 嵌套 (nested) 一个包不能有两个名字一样的函数。
------不支持 重载 (overload)
------不支持 默认参数 (default parameter)。
语法
func function_name( [parameter list] ) [return_types] {
函数体
}
例子
func main() {
a, b := test(1, 2, "sum")
fmt.Println("a,b : ", a, b)
dome()
}
func test(x, y int, s string) (int, string) {
// 类型相同的相邻参数,参数类型可合并。 多返回值必须用括号。
n := x + y
return n, s
}
func dome() {
fmt.Println("dome")
}
结构体 type
语法
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
其中:
- 类型名:标识自定义结构体的名称,在同一个包内不能重复。
- 字段名:表示结构体字段名。结构体中的字段名必须唯一。
- 字段类型:表示结构体字段的具体类型。
对于学习过其他语言的同志来说可以理解为是对象属性,只是不存在方法
栗子:
type go_class struct {
class_name string
class_stage int
}
func main() {
fmt.Println(go_class{"go class", 1}) //输出 {go class 1}
var g go_class
g.class_name = "shineyork go class"
g.class_stage = 1
fmt.Println("课程名: ", g.class_name)
fmt.Println("课程阶段: ", g.class_stage)
}
go语言中的init与main函数
main 函数
Go语言程序的默认入口函数(主函数):func main()
函数体用{}一对括号包裹。
func main(){
//函数体
}
main函数只能用于main包中,且只能定义一个。如同PHP框架中的index.php
init 函数
go语言中init函数用于包(package)的初始化,该函数是go语言的一个重要特性。可以理解为如同其他语言中的面向对象
func init() {
}
特征:
- init函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等
- 每个包可以拥有多个init函数
- 包的每个源文件也可以拥有多个init函数
- 同一个包中多个init函数的执行顺序go语言没有明确的定义(说明)
- 不同包的init函数按照包导入的依赖关系决定该初始化函数的执行顺序
- init函数不能被其他函数调用,而是在main函数执行之前,自动被调用
栗子:
var name string
func init() {
name = "shineyork"
}
func main() {
fmt.Println(name)
}
对同一个go文件的init()调用顺序是从上到下的。
对同一个package中不同文件是按文件名字符串比较“从小到大”顺序调用各文件中的init()函数。
对于不同的package,如果不相互依赖的话,按照main包中"先import的后调用"的顺序调用其包中的init(),如果package存在依赖,则先调用最早被依赖的package中的init(),最后调用main函数。
如果init函数中使用了println()或者print()你会发现在执行过程中这两个不会按照你想象中的顺序执行。这两个函数官方只推荐在测试环境中使用,对于正式环境不要使用。
import 和 package 的使用
golang使用package来管理定义模块,可以使用import关键字来导入使用。
如果导入的是go自带的包,则会去安装目录$GOROOT/src按包路径加载,如fmt包
如果是我们go get安装或自定义的包,则会去$GOPATH/src下加载
package的定义
注意相信对很多phper来说遵循PSR4的Namespace会将与路径紧密相关命名空间也作为类名的一部分,而golang则只将模块目录文件夹名作为包名,前面的路径只是用来导入而和包名无关,还是有一点需要注意的。
package的存放位置是以$GOPATH/src作为根目录,然后灵活的按照目录去组织,且包名需与最后一级目录名一致。
例如我们自定义baz包,包模块的存放位置则为$GOPATH/src/foo/bar/baz, baz 包的源码都存放在此目录下,foo/bar/baz则作为包路径被import载入。
我们需要规范的将baz包中源码的package定义为baz,就定义好一个可import载入的的包了。
自己操作理解:
GOPATH\src 目录下 或 Path\src 目录下新建 文件夹 sms
sms文件下新建ali文件夹 和 email.go、qq.go
D:\phpstudy_pro\go\src\sms\email.go
package sms //sms为文件夹
package sms
import "fmt"
func Email(){
fmt.Println("sms:email")
}
D:\phpstudy_pro\go\src\sms\qq.go
package sms
import "fmt"
func Qq(){
fmt.Println("sms:qq")
}
D:\phpstudy_pro\go\src\sms\ali\zhifubao.go
package ali
import "fmt"
func Yun(){
fmt.Println("sms\\ali:yun")
}
注意作用域
- 声明在函数内部,是函数的本地值,类似private
- 声明在函数外部,是对当前包可见(包内所有.go文件都可见)的全局值,类似protect
- 声明在函数外部且首字母大写是所有包可见的全局值,类似public
import 的定义
package main
import (
"fmt"
"sms"
"sms/ali"
)
func main(){
sms.Email() //sms:email
sms.Qq() //sms:qq
ali.Yun() //sms\ali:yun
}
普通导入就是按照加载机制,将要使用的包导入进来,然后使用 packageName.MethodName 的方式调用包内的方法即可。注意如果要包方法在其他包中可以调用,包方法需要首字母大写,例如:fmt.Println()
fmt.Printf()。
别名方式
如果两个包的包名存在冲突时,我们可以使用别名导入来解决。
package main
import (
"fmt"
"sms"
smsAli "sms/ali"
)
func main(){
sms.Email() //sms:email
sms.Qq() //sms:qq
smsAli.Yun() //smsAli 就是别名
}
下划线
在包中运用
D:\phpstudy_pro\go\src\sms\email.go
package sms
import "fmt"
func init() {
fmt.Println("init-sms:email")
}
func Email() {
fmt.Println("sms:email")
}
D:\phpstudy_pro\go\src\sms\ali\zhifubao.go
package ali
import "fmt"
func init() {
fmt.Println("init-sms-ali:yun")
}
func Yun(){
fmt.Println("sms\\ali:yun")
}
测试执行
package main
import (
"fmt"
"sms"
_ "sms/ali"
)
func main(){
sms.Email()
sms.Qq()
//ali.Yun() //不注释的话 undefined: ali 报错
}
init-sms:email
init-sms-ali:yun
sms:email
sms:qq
import 下划线(如:import hello/imp)的作用:当导入一个包时,该包下的文件里所有init()函数都会被执行,然而,有些时候我们并不需要把整个包都导入进来,仅仅是是希望它执行init()函数而已。这个时候就可以使
用 import 引用该包。即使用【import _ 包路径】只是引用该包,仅仅是为了调用init()函数,所以无法通过包名来调用包中的其他函数。
下划线在代码中的运用
package main
import "fmt"
func main() {
a, _ := compare(1)
fmt.Println(a)
}
func compare(a int) (int, error) {
return a, nil
}
解释1:
- 下划线意思是忽略这个变量.
- 比如compare,返回值为int, error
- 普通写法是a,err := compare(1)
- 如果此时不需要知道返回的错误值
- 就可以用a,_ := compare(1)
- 如此则忽略了error变量
解释2:
- 占位符,意思是那个位置本应赋给某个值,但是咱们不需要这个值。
- 所以就把该值赋给下划线,意思是丢掉不要。
- 这样编译器可以更好的优化,任何类型的单个值都可以丢给下划线。
- 这种情况是占位用的,方法返回两个结果,而你只想要一个结果。
- 那另一个就用"_"占位,而如果用变量的话,不使用,编译器是会报错的。
下一篇:go流程控制和集合 02
上一篇:go介绍安装入门