go语言开发的两个框架
beego:中国人写的
gin:老外写的(两个大学生)+gorm(orm)
go1.5以后源码都是go语言自己写的
go语言注释
单行注释 //
多行注释 /* */
包文件
当创建一个.go文件时,文件内部的首行会自动写上 package “文件所属的当前文件夹名”
package 文件夹名
package main // 表示当前go文件属于main包,在这句话上面不能写任何代码
第一个go程序
// go是编译型语言,编译型语言都需要有一个入口,入口就是改文件所属的包的包函数,比如:package main ,入口就是main函数,出口就是main函数执行完毕,所有的函数调用,都从main开始。
package main
import "fmt"
func main () {
fmt.Println("hello world")
}
// 之后右键run就可以运行了,但是go语言是编译型语言,这里没有编译成.exe文件就直接运行了,为啥?这是golang编辑器提供的,如果使用的是微软提供的vs code 编辑器就没有右键运行一说,必须要先编译,才能调用系统原生线程执行.exe文件。
那么如何编译?
// 先编译再执行
在golang终端直接执行下面命令:
go build 文件名
go build s1.go
生成.exe文件,终端直接执行.exe 文件
// 注意:在不同平台编译的执行的文件格式不一样,编译成Linux系统中执行文件,就不是.exe了。
go语言关键字
Go 语言中关键字有25个,关键字不能用于自定义名字,只能在特定语法结构中使用。
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
保留字
go语言中有37个保留字,主要对应内建的常量,类型和函数
内建常量: 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 clase delete
complex real imag
ponic recover
注意
1.这些保留字并不是关键字,可以在定义中重新使用他们。在一些特殊的场景中重新定义它们也是有意义的,但是也要注意避免过度而引起语义混乱。
2.如果一个名字是在函数内部定义,那么它就只在函数内部有效。如果是在函数外部定义,那么将在当前包的所有文件中都可以访问。名字的开头字母的大小写决定了名字在包外的可见性,如果一个名字是大写字母开头的(必须是在函数外部定义的包级名字:包级函数名本身也是包级名字),那么它将是导出来的,也就是说可以被外部的包访问,例如fmt包的Printf函数就是导出的,可以再fmt包外部访问,包本身的名字一般总是用小写字母。
3.名字的长度没有逻辑限制,但是Go语言的风格是尽量使用短小的名字,对于局部变量尤其是这样,你会经常看到i之类的短名字,而不是冗长的theLoopindex命名,通常来说,如果一个名字的作用域比较大,生命周期也比较长,那么用长的名字将会更有意义。
4,在习惯上,Go语言程序员推荐使用驼峰式命名,当名字由几个单词组成时优先使用大小写分隔,而不是优先使用下划线分隔,因此,在标准库QuoteRuneToASCII和parseRequestLine这样的函数命名,但是一般不会用quote_rune_ASCII和parse_request_line这样命名,而像ASCII和HTML这样的缩略词则避免使用大小写混合的写法,他们可能被称为htmlEscape,HTMLEscape或escapeHTML,但不会是escapeHtml。
5.go文件的名字,建议用下划线的方式命名(参见go源码)
函数
函数的参数
函数如果使用参数,该变量可称为函数的形参。
形参就像定义在函数体内的局部变量。
调用函数,可以通过两种方式来传递参数:
值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
fmt.Printf("交换前 a 的值为 : %d
", a )
fmt.Printf("交换前 b 的值为 : %d
", b )
/* 通过调用函数来交换值 */
swap(a, b)
fmt.Printf("交换后 a 的值 : %d
", a )
fmt.Printf("交换后 b 的值 : %d
", b )
}
/* 定义相互交换值的函数 */
func swap(x, y int) int {
var temp int
temp = x /* 保存 x 的值 */
x = y /* 将 y 值赋给 x */
y = temp /* 将 temp 值赋给 y*/
return temp;
}
引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int= 200
fmt.Printf("交换前,a 的值 : %d
", a )
fmt.Printf("交换前,b 的值 : %d
", b )
/* 调用 swap() 函数
* &a 指向 a 指针,a 变量的地址
* &b 指向 b 指针,b 变量的地址
*/
swap(&a, &b)
fmt.Printf("交换后,a 的值 : %d
", a )
fmt.Printf("交换后,b 的值 : %d
", 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(){
test()
test1(a:1,b:2)
test2(a:1,b:2,c:"md")
var a int=test3(a:1,b:2) // 或者写成另外两种变量形式:var a=test(2,3) a:=test3(1,2)
// 返回值的结果赋值给变量a,相当于又重新定义了一个变量,定义的变量就要使用,不然报错。
fmt.Println(a)
//方式1:
a,b:=test4(a:1,b:2) // python中可以用一个值来接收,go不允许,返回几个值,就用几个值来接收
//方式2:
// var a,b int
// a,b = test4(a:1,b:2)
fmt.Println(a)
fmr.Println(b)
//忽略掉b不接收,用“_” 下划线, (跟python不一样,python中_也是一个变量,go中没有就是没有)
a,_,c :=test5(2,3)
fmt.Println(a,c) //Println这个函数可以接收任意长度的参数
//fmt.Println(_) // 报错
test6(a...1,2,34,5,6,6,34,7,8,55)
test7(a:1,b:"ok")
}
// 1.函数定义格式
// func关键字 函数名(参数1 类型,参数2 类型)[返回值类型]{函数体内容}
//1 函数基本定义(放在main前后都可以)
func test() {
fmt.Println("我是函数test")
}
// 2.带参数的函数
func test1(a int,b,int) {
fmt.Println(a+b)
}
// 2.1带参数,且参数类型相同,形参有几个,对应的实参就要传几个,不然报错
func test2(a,b int,c string) {
fmt.Println(a+b)
}
// 3.带返回值,需要指定返回值的类型
func rest3(a,b int) int { // 后面这个int就是指定返回值的类型
return a+b
}
// 3.1 多返回值 这里返回的是两个int类型
func rest4(a,b int) (int,int) { // 后面int就是指定返回值的类型,指定类型的数量要与返回的个数相同。
return a+b,a*b
}
// 3.2 多个返回值,不想接收某个或某些返回值,用"_"来接收,
func test5(a ,b int) (int,int,string) {
return a+b,a*b,"ok"
}
// 4.可变长 a...可以接收任意长度的参数
func test6(a ...int){
fmt.Println(a)
}
// 5.go当中只有位置参数,没有关键字参数一说
func test7(a int,b string) {
fmt.Println(a)
fmt.Println(b)
//6.匿名函数(没有名字的函数),一定要定义在函数内部
// 方式1:匿名函数直接加括号
func test() {
func (){
fmt.Println("我是匿名函数")
}() //直接加括号调用
//方式2:赋值给一个变量
var a func()
a =func (){
fmt.Println("我是匿名函数")
}
a() // 引用加括号调用
// //a是个什么类型
// fmt.Printf("%T",a) // func() 所以a是一个func()类型
//
//}
}
命名返回值
package main
import "fmt"
func main() {
fmt.Println(test(1,2))
}
// 命名返回值(return直接将函数体命名的变量携带出去)
func test(a,b int) (c int,d string) {
c=10
d="成功"
return
}
闭包函数
定义在函数内部,对外界作用域有引用。
和Python不同,在go语言中,在函数内部定义函数是不能有名字的,不然报错。
函数是一等公民即函数与字符串数组整型无异,它可以被命名,可以被赋值,可以当作参数被传进另一个函数,也可以被另一个函数当作返回值可以放在任何位置。在go和Python中函数都是一等公民,在Java中却不是。
package main
import "fmt"
func main() {
a:=test(3)
a()
}
func test(m int) (func()) {
b:=func() {
fmt.Println(m)
fmt.Println("我是内层函数")
}
return b
}
// 在闭包函数内部调用外部函数(无参数)
package main
import "fmt"
func main() {
a:=test1
a=test(a)
a() // 匿名函数func()
}
func test(a func()) func() {
b:=func() {
fmt.Println("进入闭包函数.....")
a() // test1()
fmt.Println("内部函数的代码执行完了....")
}
return b
}
func test1() {
fmt.Println("我是test1函数....")
}
/*
进入闭包函数.....
我是test1函数....
内部函数的代码执行完了....
*/
// 带参数和返回值的
package main
import "fmt"
func main() {
a:=test()
b:=a(1,2)
b()
// type 起别名,让冗杂的代码看上去更加清晰
type MyInt int
var in MyInt=10
fmt.Println(in)
}
// 类型起别名
type MyFunc func(a int,b int) func()
func test() MyFunc {
c:=func(a,b int) func(){
d:=func(){
fmt.Println("最里层了")
}
return d
}
return c
}
/*
*/
type起别名,类型转换
func main() {
type MyInt int
var a MyInt=10
var b int=90
// a=b go是强类型语言,a的类型起了别名,b是int类型,两者类型不一样
a=MyInt(b)
fmt.Println(a)
fmt.Printf("%T",a)
}
/*
90
main.MyInt
*/
关于interface{}
interface{}是所有类型的鼻祖,叫匿名空接口,int、string、float32都属于interface{}类型
// Println函数可以传任意的数据类型
fmt.Println(a...1,"zhang",2.4)
包的使用
便于文件管理,在使用go开发的时候,就要分包。如果在一个包中要使用另一个包下的函数,前提是这些包都在go/src下的同级目录下。要被使用的那个包的下所有的文件夹下的哪个函数名或变量名想要被使用,就需要将其名字定义成首字母大写,这样才能跨包使用,默认定义的小写的函数或变量名只能在包内部使用。
// 案例
package main
import (
"fmt"
"go_code/mypackage"
)
func main() {
mypackage.Test1() // 直接写上包名 点 就会弹出包中大写的函数名
fmt.Println(mypackage.Name)
}
/*
3
xxxx
zhang
*/
// 被导入包
//s1.go
package mypackage
import "fmt"
var Name string="zhang"
func Test1() {
fmt.Println(test2(1,2))
fmt.Println("xxxx")
}
// s2.go
package mypackage
func test2(a,b int ) int {
return a+b
}
if-else的使用
语法格式:
func main() {
//1 语法
/*
if 条件 {
//符合上面条件的执行
}
else if 条件{
//符合上面条件的执行
}else {
// 不符合上面的条件执行这个
}
*/
}
package main
import "fmt"
func main() {
// 第一种书写方式:
var a =10
if a<9{
fmt.Println("小于9")
}else if a==10{
fmt.Println("10")
}else {
fmt.Println("都不符合")
}
// 第二种书写方式:
//作用域范围不一样,这里的变量a只能在if判断内部使用。
if a:=10;a<9{ // 条件和大括号必须在一行
fmt.Println("小于9")
}else if a==10{
fmt.Println("10")
}else {
fmt.Println("都不符合")
}
// fmt.Println(a)只能找到全局的变量,不能找到if局部的变量a
}
for循环
for循环的三部分,其中第一部分和第三部分可以移到别的地方,条件也不是必须的。
package main
import "fmt"
// 正常书写格式
func main() {
for i:=0;i<10;i++ {
fmt.Println(i)
}
}
// 把初始变量拿到上面
func main() {
i:=0
for ;i<10;i++ {
fmt.Println(i)
}
}
// 把i++放到循环内部
func main() {
i:=0
for ;i<10; {
fmt.Println(i)
i++
}
}
// 无限制条件,变成了死循环。
func main() {
i:=0
for ;; {
fmt.Println(i)
i++
}
}
// 全部省略的简略写法,死循环
func main() {
for {
fmt.Println("aaaaa")
}
}
// for 条件{ 就是while循环
//
//}
for循环中的break
用于循环语句中跳出循环,并开始执行循环之后的语句。
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* for 循环 */
for a < 20 {
fmt.Printf("a 的值为 : %d
", a);
a++;
if a > 15 {
/* 使用 break 语句跳出循环 */
break;
}
}
}
for 循环的continue
Go 语言的 continue 语句 有点像 break 语句。但是 continue 不是跳出循环,而是跳过当前循环执行下一次循环语句。
for 循环中,执行 continue 语句会触发 for 增量语句的执行。
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* for 循环 */
for a < 20 {
if a == 15 {
/* 跳过此次循环 */
a = a + 1;
continue;
}
fmt.Printf("a 的值为 : %d
", a);
a++;
}
}
for 循环嵌套
// 使用循环嵌套来输出 2 到 100 间的素数:
package main
import "fmt"
func main() {
/* 定义局部变量 */
var i, j int
for i=2; i < 100; i++ {
for j=2; j <= (i/j); j++ {
if(i%j==0) {
break; // 如果发现因子,则不是素数
}
}
if(j > (i/j)) {
fmt.Printf("%d 是素数
", i);
}
}
}
// 九九乘法表
package main
import "fmt"
func main() {
for m := 1; m < 10; m++ {
/* fmt.Printf("第%d次:
",m) */
for n := 1; n <= m; n++ {
fmt.Printf("%dx%d=%d ",n,m,m*n)
}
fmt.Println("")
}
}
函数装饰器
// 普通装饰器
package main
import "fmt"
func user_logging(fun func()) func() func() {
wrapper := func() func(){
fmt.Println("this func is", fun)
fmt.Println("the end of foo")
return fun
}
return wrapper
}
func foo() {
println("i am foo")
}
func main() {
foo := user_logging(foo)
fmt.Println(foo())
}
//this func is 0x490840
//the end of foo
//0x490840
package main
import "fmt"
func user_logging(fun func()) func() { // 装饰器函数
wrapper := func() {
fmt.Println("this func is", fun)
fun()
fmt.Println("the end of foo")
}
return wrapper
}
func foo() {
println("i am foo")
}
func main() {
foo := user_logging(foo)
foo()
}
//this func is 0x490840
//i am foo
//the end of foo
// 功能函数加参数
package main
import (
"fmt"
"time"
)
func show_time(fun func(...int)) func(...int) { // 装饰器函数
wrapper := func(args ...int) {
start := time.Now().Unix()
fun(args...)
end := time.Now().Unix()
fmt.Println(start, end)
fmt.Printf("spend %d", end - start)
}
return wrapper
}
func add(args ...int) { // 功能函数
sums := 0
for _, v := range args {
sums += v
}
fmt.Println(sums)
time.Sleep(3 * time.Second)
}
func main() {
add := show_time(add)
add(1, 2, 3, 4, 5)
}
// 装饰器函数加参数
package main
import (
"fmt"
"time"
)
func logger(flag bool) func(fun func(...int)) func(...int) {
show_time := func(fun func(...int)) func(...int) { // 装饰器函数
wrapper := func(args ...int) {
start := time.Now().Unix()
fun(args...)
end := time.Now().Unix()
fmt.Println(start, end)
fmt.Printf("spend %d
", end - start)
if flag == true {
fmt.Println("日志记录")
}
}
return wrapper
}
return show_time
}
func add(args ...int) { // 功能函数
sums := 0
for _, v := range args {
sums += v
}
fmt.Println(sums)
time.Sleep(3 * time.Second)
}
func test() {
show_time := logger(false)
add := show_time(add)
add(1, 2, 3, 4, 5)
}
func main() {
show_time := logger(true)
add := show_time(add)
add(1, 2, 3, 4, 5)
test()
}
//15
//1554351453 1554351456
//spend 3
//日志记录
//15
//1554351456 1554351459
//spend 3
// 通过反射实现的通用型装饰器
package main
import (
"fmt"
"reflect"
)
func Decorator(decoPtr, fn interface{}) (err error) {
var decoratedFunc, targetFunc reflect.Value
decoratedFunc = reflect.ValueOf(decoPtr).Elem()
targetFunc = reflect.ValueOf(fn)
v := reflect.MakeFunc(targetFunc.Type(),
func(in []reflect.Value) (out []reflect.Value) {
fmt.Println("before")
args := []reflect.Value{}
if len(in) == 1 && in[0].Kind() == reflect.Slice {
for i := 0; i < in[0].Len(); i++ {
args = append(args, in[0].Index(i))
}
in = args
}
out = targetFunc.Call(in)
fmt.Println("after")
return
})
decoratedFunc.Set(v)
return
}
func foo(a, b, c int) int {
fmt.Println(a)
return b
}
func main() {
myfoo := foo
Decorator(&myfoo, foo)
myfoo(1, 2, 3)
}
//before
//1
//after