自己啃官网, 搞成能用的系统;
]golang语言环境
下载地址:http://go.p2hp.com/#google_vignette
一直下一步安装,完成 cmd: go version看版本,是否安装成功
在文件管理器地址栏 最前面cmd+空格 回车,直接跳到cmd该目录下
]环境变量
GOROOT
系统环境变量 新建 安装golang的地址:
D:\bread\go\Environment
GOPATH 项目本地保存地址:
D:\bread\go\LearningDocuments{目录下建src,pkg,bin文件夹,以后开发用}
系统的 path环境变量 选项 新建一个环境变量: D:\bread\go\Environment\bin
]cmd下go env 查看go相关工作配置
D:\bread\go\LearningDocuments>go env
set GO111MODULE= #
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\85456\AppData\Local\go-build
set GOENV=C:\Users\85456\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\85456\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=D:\bread\go\LearningDocuments #代码存放地址
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=D:\bread\go\Environment #
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=D:\bread\go\Environment\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.17.3
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=NUL
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\85456\AppData\Local\Temp\go-build3762675728=/tmp/go-build -gno-record-gcc-switches
]txt 运行
在 hello.go目录的cmd 中 go run hello.go文件夹;
编译器 GoLand jetbrain大礼包
破解: https://www.bilibili.com/read/cv19022444 方法
激活码:https://docs.qq.com/doc/DZWFmak1WcVBhdENu
破解软件:D:\bread\go\jihuo-tool
语法开始
package main //main 包
import "fmt" //输出工具
func main() {//无结尾符号 ,英文双引号; 程序入口
fmt.Println("Hello, World!")
}
]注释
单行//
多行/* */
格式字符串 输入输出
//输出打印 格式化字符串,fmt.Printf()
字符串的占位符:
%d 数字, %p 内存地址, %t布尔类型? ,\n换行 , %f 浮点数,%.1f5舍6入保留一位小数,%s字符串的占位符; %T 变量类型; %v切片
//获取变量地址 &变量名 取地址符:&
输出
fmt.Println(name, age)//输出完换行
fmt.Printf("类型:%T,值%s\n", s1, s1)//格式化输出
fmt.Print()输出不换行
输入
获取输入 fmt.Scanln();//接收输入 换行结束
fmt.Scan(&a);//获取a变量的地址,接收输入数据,赋值给变量a
fmt.Scanf();
遇到scan() 程序阻塞等待键盘输入
]变量
X. 声明/定义,初始化赋值 语法
显式声明
var name string = "lu"
var 变量名 数据类型 = 变量值
静态语言类型 必须显示声明变量类型
定义了变量一定要用,否则报错
一次定义多个变量
//声明多个变量
//1.一行声明多个变量,类型必须一样
var var4, var5, var6 string="ww" ,"22","rr"
fmt.Println(var4, var5, var6)
var var1, var2, var3 int //声明但未赋值,系统自动初始化类型的默认值,
fmt.Println(var1, var2, var3)
//2.var()一次,多行声明多个变量,类型可以不一样
var (
sex string //声明但不赋初始值, 系统会赋类型的初始值,string 空字符串 ""
high int //默认值0
isFemale bool //默认 false
xiongWei float64 //0.0
//切片, 函数,指针变量的默认未null
)
fmt.Println(sex, high, isFemale, xiongWei)
var var7,var8 bool
var7 = var8 =false 不能这样写
var7=false
var8=false
变量命名 驼峰
x.短变量声明并初始化
x.短变量声明并初始化, 自动推断变量类型:
限制: 不能提供数据类型; 定义/声明时必须初始化; 只能用在函数内部, 已经定义过的变量不能用这个语法
name2 := "露露"
age1 := 30
fmt.Println(name2, age1)
打印变量类型 %T
fmt.Printf("%T",%T", name2, age1) //%T表示type
打印变量地址
打印变量地址 变量值变了,但是内存地址不会变. 每次启动机器会重新分配新地址.
//输出打印 格式化字符串,fmt.Printf() 字符串的占位符 %d 数字, %p 内存地址 %t布尔类型? \n换行 %f 浮点数 //获取变量地址 &变量名 取地址符:& age1 := 30 fmt.Println("数字:%d,内存:%p", age1, &age1) //数字:string,内存int数字:30,内存0xc00001a088 age1 = 200 fmt.Printf("数字:%d,内存:%p", age1, &age1) //数字:200,内存0xc00001a088
交换变量
其他:需要中间变量 C#/java/C等 a, b, temp temp=a a=b b=temp
//变量交换
var a int = 100
var b int = 200
b, a = a, b
fmt.Println(a, b)
匿名变量
'_' 空白标识符 ,任何类型都可以赋值给他, 但是任何赋值给这个变量的值都将被抛弃, 不占内存空间,不分配内存;
用处:接收多个返回值时,如只需要部分,其他的就用'_'代替,抛弃.
变量的作用域
变量,常量,函数的作用范围
局部变量
一般:函数体内声明的变量 var name string="张三"
全局变量
main()函数外定义的变量,
局部变量会覆盖同名的全局变量
常量
显示定义
隐式定义 ,可省略类型,可以推断常量的类型
可一行同时定义多个常量.这样写,必须都赋值,类型可以不一样
一次定义多个常量,const()多行写法 ,
第一行的常量必须赋值(值可以是string,int,bool,iota(特殊的常量,值是int)).
后面行的常量可以不赋值,不赋值值时,默认和上一行常量的值一样.
iota一个特殊系统常量. 一个const定义中常量的行索引.
每次遇到const关键字,系统都将iota的值设为0, 0索引行,
const内每加一行常量定义,iota的值都+1, 1索引行,2索引行... 可以叫 const中的常量行计数器.
//常量
const c1 string = "存款100万" //显示定义
const c2 = 100 //隐式定义,可以推断常量的类型
const c3, c4, c5 = "str", 100, false //一行同时定义多个常量.这样写,必须都赋值
fmt.Println(c3, c4, c5)
const c6, c7, c8 = "steel", iota, iota ////iota一个特殊系统常量. 一个const定义中常量的行索引.
// 每次遇到const关键字,系统都将iota的值设为0, 0索引行,const内每加一行常量定义,iota的值都+1, 1索引行,2索引行...
fmt.Println(c6, c7, c8) //steel,0,0 第0行常量
const (
c9 = 10 //const()写法,定义多个常量时,第一行的常量必须赋值.
c10 //不赋值值时,默认和上一个常量的值一样
c11
c12 = "str"
c13
)
fmt.Println(c9, c10, c11, c12, c13) //10 10 10 str str
const (
c14 = iota // 0索引行
c15 // 不赋值值时,默认和上一行常量的值一样 此处就是iota, 值是1. 行索引为1. 等效于 c15=iota.
c16 //每加一行 iota都+1
c17 = "str" ////每加一行 iota都+1
c18
c19 = iota ////每加一行 iota都+1 5索引行
c20 //6索引行
)
fmt.Println(c14, c15, c16, c17, c18, c19, c20) //0 1 2 str str 5 6
var name string ="lu"
var s1, s2,s3 int = 1,2,3
var s4, s5 string
s4="tr"
s5="bb"
var (
v1 string
v2 int
v3 bool
)
数据类型
值类型:
引用类型:切片,
布尔类型
var isFlag bool
fmt.Println("布尔值的默认值:", isFlag)//false
数字型
//整型
var nian int = 18 //默认int64,默认值0 uint无符号
fmt.Printf("类型:%T,值%d\n", nian, nian)
//浮点型 一般不用来计算;
var cai float64 = 30.26 //默认float64,默认值0.000000 六位, 七位小数时float32会丢失精度;
fmt.Printf("类型:%T,值%f\n", cai, cai)
fmt.Printf("类型:%T,值%.1f\n", cai, cai) //格式可以,控制小数位数, 4,5舍 6入 什么规则?就近?
//别名 byte:uint8,rune:int32,int:int64
字符串
> 字符串在go中是值类型 数组也是值类型
//别名 byte:uint8,rune:int32,int:int64
//string类型 go的字符串是由单个字节连接起来的,go语言的字符串的字节使用UTF-8编码标识的Unicode文本
//字符 '' 字符--整型 映射表:ASCII字符码; GBK中文编码; Unicode 世界统一编码. 取字符的数字类型值,就是编码表中的值
ch1 := 'A'
fmt.Printf("类型:%T,值%d\n", ch1, ch1) //类型:int32,值65
fmt.Println(ch1)//65
s1 := "A" //字符
fmt.Printf("类型:%T,值%s\n", s1, s1)//类型:string,值A
//字符串连接 +
fmt.Println("hello" + "田野")
//转义字符 \
// \" \n换行;\t制表符
字符
var bcha int32 = 'B'
fmt.Println(bcha)//66
类型转换
//数据类型转换: 必须显示声明
//转换后的变量 := 要转换的类型(变量)
a_t := 3
b_t := 5.00
c_t := float64(a_t)
d_t := int(b_t)
fmt.Printf("类型:%T\n", c_t)
fmt.Printf("类型:%T\n", d_t)
//整型...是不能转换为bool类型的
//同样注意精度丢失的问题;
指针
Go 拥有指针。指针保存了值的内存地址[A pointer holds the memory address of a value.]。 通过指针就能获得值
类型 *T
是指向 T
类型值的指针。其零值为 nil
[**The type *T
is a pointer to a T
value. Its zero value is nil
. **]。
var p *int
var s_p *string
&
操作符会生成一个指向其操作数的指针[**The &
operator generates a pointer to its operand. **]。
i := 42
p = &i
s := "字符串"
s_p = &s
fmt.Println("s的指针s_p,值:", s_p)
*
操作符表示指针指向的底层值[The *
operator denotes the pointer's underlying value.]。
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i
fmt.Println("利用*+指针变量读取 指针指向的底层值:", *s_p) //指针指向的底层值, 即内存中实际数据的值;
*s_p = "新字符串" //也可以利用来赋值
fmt.Println("利用*+指针变量读取, 指针指向的底层值:", *s_p)
这也就是通常所说的“间接引用”或“重定向”。
[类型T的变量b, &b获取变量b的指针变量p , *p *操作符+p指针变量,读取指针底层]与 C 不同,Go 没有指针运算。
结构体
一个结构体(struct
)就是一组字段(field)。
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})//V: {1 2}
}
结构体字段
结构体字段使用点号来访问。
v := V{3, 4}
fmt.Println("结构体字段v.X:", v.X)
结构体指针
结构体字段可以通过结构体指针来访问。
如果我们有一个指向结构体的指针 p
,那么可以通过 (*p).X
来访问其字段 X
。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X
就可以。
var v_p *V
v_p = &v //结构体 实例 的指针 &{3 4}
fmt.Println("结构体 实例 的指针:", v_p)
fmt.Println("用结构的指针访问结构字段:", (*v_p).X)
fmt.Println("用结构的指针访问结构字段:", v_p.X) //隐式间接访问
结构体文法
结构体文法通过直接列出字段的值来新分配一个结构体。
使用 Name:
语法可以仅列出部分字段。(字段名的顺序无关。)
特殊的前缀 &
返回一个指向结构体的指针。
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // 创建一个 Vertex 类型的结构体
v2 = Vertex{X: 1} // 创建一个 Vertex 类型的结构体
v3 = Vertex{} // X:0 Y:0
p = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)
func main() {
fmt.Println(v1, p, v2, v3)
}
数组
类型 [n]T
表示拥有 n
个 T
类型的值的数组。[注意书写语法:最后一个元素换行时的,]
数组的长度是其类型的一部分,因此数组不能改变大小。
var sa [2]string
sa[0] = "2022"
sa[1] = "世界杯"
fmt.Println(sa[0], sa[1])//[2022 世界杯]
fmt.Println(sa)
si2 := [4]int{1, 2, 3, 4}
fmt.Println(si2)
[注意书写语法:最后一个元素换行时的,]
切片
<切片大小可变
切片大小可变, 数组的灵活视图;A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array.
类型 []T
表示一个元素类型为 T
的切片。
切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:
a[low : high]
它会选择一个半开区间,包括第一个元素,但排除最后一个元素。
si3 := [6]int{11, 22, 33, 44, 55, 66}
slice1 := si3[0:2]
fmt.Println("si3索引0到2)的切片是:", slice1)
var slice2 []int = []int{11, 22, 33}//语法和数组类似
fmt.Println("切片能实例化吗:", slice2)//可以的.
可以实例化并赋初始值
<切片可包含任何类型
切片可包含任何类型,甚至包括其它的切片。 当然一次只能包含一种;
// 创建一个井字板(经典游戏)
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
// 两个玩家轮流打上 X 和 O
board[0][0] = "X"
board[2][2] = "O"
board[1][2] = "X"
board[1][0] = "O"
board[0][2] = "X"
for i := 0; i < len(board); i++ {
fmt.Printf("%s\n", strings.Join(board[i], " "))
}
<切片就像数组的引用
切片就像数组的引用.切片并不存储任何数据,它只是描述了底层数组中的一段。
更改切片的元素会修改其底层数组中对应的元素。
与它共享底层数组的切片都会观测到这些修改。
<切片语法
这是一个数组文法:
[3]bool{true, true, false}
下面这样则会创建一个和上面相同的数组,然后构建一个引用了它的切片:
[]bool{true, true, false}
<默认/缺省 上下界
在进行切片时,你可以利用它的默认行为来忽略上下界。
切片下界的默认值为 0
,上界则是该切片的长度。
对于数组
var a [10]int
来说,以下切片是等价的:
a[0:10]
a[:10]
a[0:]
a[:]
<切片长度,容量
长度 len(s []T), 切片中元素的个数
容量cap(s []T),从切片下界在底层数组中的索引对应的元素开始, 到底层数组最后一个元素为止,**The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice. **
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
<nil 切片
切片的零值是 nil
。
nil 切片的长度和容量为 0 且没有底层数组。
var s []int
fmt.Println(s, len(s), cap(s))//切片的零值nil:[],nil的长度:0,容量:0
if s == nil {
fmt.Println("nil!")
}
[注意书写语法:最后一个元素换行时的,]
Need a trailing comma before a newline in the composite literal.复合字面值的换行符前需要一个尾随逗号
使用make 创建切片
用 make 创建切片
切片可以用内建函数 make
来创建,这也是你创建动态长度数组的方式。Slices can be created with the built-in make
function; this is how you create dynamically-sized arrays.
make
函数会分配一个元素为零值的数组并返回一个引用了它的切片:The make
function allocates a zeroed array and returns a slice that refers to that array:
要指定它的容量,需向 make
传入第三个参数:切片类型;切片长度;切片容量
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
算术运算符
+-*/% ++ --
流程语句
if c1124 > 100 {
fmt.Println("大于100")
} else {
fmt.Println("小于等于100")
}
Switch
//switch 可以跟任意变量
switch c1124 {
case 60:
fmt.Println("刚及格")
case 70:
fmt.Println("70")
case 80, 90:
fmt.Println("80,.90")
default:
fmt.Println("兜底条件")
}
//switch不跟变量, 默认true
switch {
case false:
fmt.Println("false")
case true:
fmt.Println("true")
default:
fmt.Println("default")
}
// case 穿透 fallthrough 遇到它时后面的都穿透执行
//想停止, break
var e int = 70
switch e {
case 60:
fmt.Println("刚及格")
case 70:
fmt.Println("70")
fallthrough //穿透该层,继续执行下一个case
case 80:
//break 就不执行了
fmt.Println("80")
case 12:
fmt.Println("12")
default:
fmt.Println("兜底条件")
}
//for循环 就是没()
for i := 0; i < 5; i++ {
fmt.Println("打印次数:", i)
}
★函数
//><函数 func 函数名(参数列表) (返回值类型列表){}
func swap(x, y string) (string, string) {
return y, x
}
func lei(x, y string) (string, int) {
return y, 2
}
//接收多个返回值
va1, va2 := swap("你好", "世界")
fmt.Println(va1, va2)
va3, va4 := lei("你好", "世界")
fmt.Println(va3, va4)
//匿名变量扔掉不要的结果
va1, _ = swap("nnn", "mmm")
↑特点,返回值,可以多个, 类型可以不一样;接收按顺序
//可变参数 一个函数的参数类型确定,但是个数不确定 func variblePara(a ...int) { fmt.Println("这是一个可不参数的函数") } //可变参数 在 参数列表中的最后一个即可,前面的参数类型可以不同,如下: func append(s []T, vs ...T) []T
参数传递
值传递:传递的是数据的副本,修改数据对于原始的数据没有影响;
值类型的数据:go的基础类型,array,struct
函数外的变量通过方法的参数传入函数内,在方法内部修改参数,不会改变方法外的变量值. 传入的是值的副本;
对比,引用传递; 操作的是数据的地址: slice ,map, chanel...
切片,可以扩容的数组;
变量作用域
函数内:作用域和其他语言差不多;
特殊之处:
//变量作用域 go特点:if内的作用域
temp := 100
if b125 := 1; b < 10 {
fmt.Println("if开头定义的局部变量b125:", b125)//1
temp := 50
fmt.Println("if中定义的局部变量temp:", temp) //50 就近原则
}
fmt.Println("if外,main函数内的局部变量temp:", temp)//100
//fmt.Println("if开头定义的局部变量b:", b125)// 类似于for
defer函数
go语言中,使用defer关键字来延迟一个函数或者方法的执行.
可以在函数中添加多个defer语句,当函数执行到最后时,这些defer语句会逆序执行
但是当程序执行到defer语句时,go已经把参数传入方法/函数了,只是延缓执行了.
作用:关闭io/网络等资源;
函数的数据类型
函数也是一种数据类型(引用类型) --func()/参数/返回值,不加()函数名就是一个变量
函数在go语言中是复合类型,可以看做是一种特殊的变量
函数名:指向函数体的内存地址,一种特殊类型的指针变量
{//函数类型
fmt.Printf("f函数的类型是%T:\n", f)//func(int)
fmt.Println("f指针变量,存着函数体的地址:", f)
//既然是数据类型,就可以实例化一个对象
var f2 func(int)
f2 = f//引用类型的 将f'func(int)函数类型'的变量赋值给实例化的变量f2
f3 := f//隐式写法也行
f2(5)//调用f2 和 f()的效果一样
f3(5)
}
func f(n int) {
fmt.Println("输入的参数是:", n)
}
匿名函数
func(){}
匿名函数调用:func(){}()
只执行一次
//匿名函数
//func(a,b int)int{
// return a+b
//}
//匿名函数调用
c2210 := func(a, b int) int {
return a + b
}(1, 2)
fmt.Println("调用匿名函数的结果:", c2210)
Go语言支持函数式编程:
1.将匿名函数作为另一个函数的参数(具名函数当然也可以,函数既然是一种类型,就可以当做参数),回调函数
高阶函数调用回调函数,回调函数可以是匿名函数.
2.将匿名函数作为另一个函数的返回值,可以行成闭包结构
//回调函数
c1126 := oper(1, 2, add)
fmt.Println("oper回调add的结果是:", c1126)
c1126 = oper(1, 2, jian)
fmt.Println("oper回调jian的结果是:", c1126)
c1126 = oper(8, 2, func(aa, bb int) int {
if bb == 0 {
return 0
} else {
return aa / bb
}
})
fmt.Println("oper回调匿名函数的结果是:", c1126)
}//main
//函数底层, 匿名函数, 函数作为参数
func oper(a, b int, f func(int, int) int) int { //oper是高阶函数
return f(a, b) //f是回调函数,可以是匿名函数
}
func add(a, b int) int { //回调函数
return a + b
}
func jian(a, b int) int { //回调函数
return a - b
}
gin框架
安装 go get --底层 git clone
安装gin
1、框架文档介绍:go get -u github.com/gin-gonic/gin
2、这时候如果遇到问题资源加载不了,解决方法是使用代理(这块有个 go env 的命令,可以查看当前配置),在cmd中运行
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct
设置后,重新运行 go get -u github.com/gin-gonic/gin 可以很快速的安装
安装后 import "github.com/gin-gonic/gin" 爆红,
settings中的
GOPROXY=https://goproxy.io
就可以用了;
创建服务, 端口, 设置网站,
支持restful api
rest请求方式隔离api
20221228 周三 gin使用
创建服务,,, 给服务指定端口,,,处理请求
-创建新项目
--创建新文件 main.go
package main
import (
"github.com/gin-gonic/gin" //引用gin包
"github.com/thinkerou/favicon" //(4) 编译器会自动下载,牛逼
"net/http"
)
func main() {
//20221228三(1)创建一个服务
ginServer := gin.Default()
//(4)配置网站图标
ginServer.Use(favicon.New("./白骷髅.ico")) //ico文件, ./ 代表项目的相对路径 ico文件放到项目目录下
//(3)[就可以运行了]访问地址,处理请求, Request Resopnse
ginServer.GET("/hello", func(context *gin.Context) {
context.JSON(200, gin.H{"msg": "返回信息.现在还差写语法基础的知识."})
}) //后台,返回给前台数据;
//(5)rest api 开发
ginServer.POST("/user", func(c *gin.Context) { //c context, tab键切换输入位置
c.JSON(200, gin.H{"msg": "测试restfuf POST方式"})
})
ginServer.PUT("/user")
//ginServer.PUT("user") 带不带/都一样
ginServer.DELETE("/user")
//20221229(6)加载静态页面
//(6.0)加载静态页面的函数 搭配 (6.1)使用
ginServer.LoadHTMLGlob("temp/*") //加载temp文件下所有的静态文件
//ginServer.LoadHTMLFiles("")//绝对路径 二选一
//(6.01)加载静态文件的函数
ginServer.Static("/static", "./static")
//(6.1)//响应一个页面给前端
ginServer.GET("/index", func(c *gin.Context) {
//c.JSON()
//返回.html页面
c.HTML(http.StatusOK, "index.html", gin.H{ //gin,H{} 给前台传key:value 的函数
"msg": "这是go后台传过来的数据.", //!!!注意这个','语法 //前台接收就行 类似vue语法
})
})
//(7)20221230网址传参 接收前端传过来的参数
// url?userid=zzz&usernanme=菜鸟凤凰 一般传参风格
ginServer.GET("/user/info", func(c *gin.Context) { //访问网址, 获取请求的上下文,后台处理请求
uid := c.Query("userid") //获取网址/请求中的参数, key获得
uname := c.Query("username")
c.JSON(200, gin.H{ //返回前台的数据
"msg": "这是用传统风格获取的url参数",
"userid": uid,
"username": uname,
})
})
// /user/info/1/菜鸟凤凰 restful传参风格
ginServer.GET("user/info/:userid/:username", func(c *gin.Context) {
uid := c.Param("userid") //获取网址/请求中的参数, key获得
uname := c.Param("username")
c.JSON(http.StatusOK, gin.H{
"msg": "这是用restful的传参风格获取的url参数",
"userid": uid,
"username": uname,
})
})
//(2)指定服务端口
ginServer.Run(":8088")
}
(4)网站图标
goLand 编辑器
厉害痕迹. 恢复文件
恢复,