下载
my)Go!!!!!
基础
结构
package main
import "fmt"
func main() {
/* 注释 */
fmt.Println("Hello, World!")
}
和python差不多,你可以格式化输出
func main() {
var hello="Hello%s"
var name="Rxiain"
fmt.Printf(heello,name)
}
变量名不能以数字开头,声明变量时你可以指定类型,belike var hello string
,没有指定内容(初始化)则数字默认为值 0
,布尔值为 False
,字符串为空,其它类型为 nil
(不是null,是nil
你可以因式分解表达一些东西使其看起来更规整
var (
v1 e1
v2 e2
)
import (
"fmt"
)
初始化声明
新东西,上例中的 var hello="Hello%s"
可以简化为 hello := "Hello%s"
,而这时相同的,所以用过 var
后再使用 :=
符号则会报错
引用&指针
和cpp一样,可以使用 &i
获得 i
的内存地址,也可以var一个指针存储指定变量的内存地址,两个变量的赋值操作也是让其指向的内存地址相同。
func main() {
var c = 1
var d = 2
var a = &c
var b = &d
fmt.Println("a:%p, b:%p", a, b)
a = b
fmt.Println("a:%p, b:%p", a, b)
}
指针声明:var var_name *var-type
belike:var ip *int
然后可以通过 *ip
访问ip指向的内存里包含的东西
常量
const
:与 var
差不多的使用形式
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。 iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
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)
}
插一嘴,go下的类型转换与cpp的结构不同,belike:int(something)
go并不支持隐式类型转换
条件判断
- 简单的if:
if a < 0 {
fmt.Printf("a<0" )
} else if{
...
} else {
...
}
- switch和cpp差不多
- select语句,这个与Go的通道、goroutlines有关,放在后面
函数
func function_name( [parameter list] ) [return_types] {
函数体
}
可以看到返回类型放置在了后面 go的函数可以返回多个值
数组
声明:var arrayName [size]dataType
初始化:var numbers = [5]int{1, 2, 3:6.0, 4, 5}
注意go的数组大小是类型的一部分,不同的大小下即使是相同的类型也不相互兼容 大小可以用 ...
表示,编译器会根据元素自行判断大小 不填大小,编译器会根据 {}
里的元素推断大小,也就是之后的元素 在 {}
里初始化元素可以指定下标
结构体
定义belike:
type Books struct {
title string
author string
subject string
book_id int
}
声明类型 var a Books
此时可以通过 a.title
调用结构体中的数据 另外,指针也可以存储结构体的变量地址
切片
动态数组,可以追加内容,声明方法与数组区别上就是不填大小,切片的使用比数组更为常见。 声明:var identifier []type
belike:slice1 := make([]type, len, cap)
其中len时原始长度,cap是最大容量
初始化:
s :=[] int {1,2,3 }
s := arr[:]
引用数列arrs := arr[startIndex:endIndex]
跟上面的差不多,只不过指定了下标范围s1 := s[startIndex:endIndex]
也可以用存在的切片来初始化
切片是可索引的,并且可以由 len() 方法获取长度。 切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
追加新元素:append()
函数,belike:numbers = append(numbers, 1)
,其中numbers是是一个切片
拷贝切片: copy
函数,belike:copy(numbers1,numbers)
,要注意 numbers1
的容量要大于等于 numbers
Map
无序的键值对集合 定义:map_variable := make(map[KeyType]ValueType, initialCapacity)
,需要指明键值的数据类型 也可以:
m := map[string]int{
"apple": 1,
"banana": 2,
"orange": 3,
}
用delete函数删除元素:delete(Map的变量,Key)
接口
接口(interface)是 Go 语言中的一种类型,用于定义行为的集合,它通过描述类型必须实现的方法,规定了类型的行为契约。
任意类型只要实现了所有方法,就被认为实现了该接口
/* 定义接口 */
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 DataUtils interface {
Get() string
}
type Person struct{
Name string
Age int
Id int
}
func (a Person) Get() string {
return fmt.Sprintf("Name: %s, Age: %d, Id: %d", a.Name, a.Age, a.Id)
}
func main() {
p := Person{
Name: "orxiain",
Age: 20,
Id: 1,
}
fmt.Println(p.Get())
}
空接口
用来实现泛型数据处理
package main
import "fmt"
func printValue(val interface{}) {
fmt.Printf("Value: %v, Type: %T\n", val, val)
}
func main() {
printValue(42) // int
printValue("hello") // string
printValue(3.14) // float64
printValue([]int{1, 2}) // slice
}
类型断言
类型断言(Type Assertion)是一种用于将接口类型的值转换为具体类型的操作
value, ok := interfaceValue.(Type)
interfaceValue
是一个接口类型的变量。Type
是你想要断言的目标类型。value
是断言后的具体类型的值(如果断言成功)。ok
是一个布尔值,表示断言是否成功.
这样用:
func main (){
var i interface{} = "Hello"
if s, ok := i.(string); ok {
fmt.Println("Value is a string:", s)
} else {
fmt.Println("Value is not a string")
}
}
搭配 switch
实现不同数据类型的不同操作
func printType(val interface{}) {
switch v := val.(type) {
case int:
fmt.Println("Integer:", v)
case string:
fmt.Println("String:", v)
case float64:
fmt.Println("Float:", v)
default:
fmt.Println("Unknown type")
}
}
错误
定义错误并使用
package main
import (
"errors"
"fmt"
)
func main() {
err := errors.New("this is an error")
fmt.Println(err) // 输出:this is an error
}
fmt.ErrrorF fmt.Errorf
是一个用于创建格式化错误消息的函数。它属于 fmt
包,可以接受一个格式化字符串和一系列参数,返回一个实现了 error
接口的对象。1.13版本之后可以用 %w
占位符包装错误
originalErr := fmt.Errorf("原始错误:文件未找到")
wrappedErr := fmt.Errorf("包装错误:%w", originalErr)
errors.Is
在 Go 语言中,errors.Is
函数用于判断一个错误链中是否包含某个特定的错误。它通常用于检查一个被包装过的错误是否包含某个基础错误
基本用法:
func Is(err, target error) bool
其中 err
是被检查的错误,target error
是检测的目标错误
- 如果
target
为nil
,则直接比较err
是否也为nil
. - 如果
err
和target
都是可比较的,并且它们相等,则返回true
. - 如果
err
实现了Is
方法,并且调用err.Is(target)
返回true
,则返回true
. - 否则,递归调用
Unwrap
方法来获取err
的下一层错误,并继续检查
使用例(什么绿幕素材靶场
package main
import (
"fmt"
"errors"
)
var BaseErr = errors.New("the underlying base error")
func main() {
err1 := fmt.Errorf("wrap base: %w", BaseErr)
err2 := fmt.Errorf("wrap err1: %w", err1)//这里err2包含了err1,err1包含了BaseErr
if errors.Is(err2, BaseErr) {
fmt.Println("err2 contains BaseErr")
} else {
fmt.Println("err2 does not contain BaseErr")
}
}
errors.As
errors.As
函数用于从一个错误链中提取指定类型的错误。它的作用是判断包装的错误链中是否存在某个特定类型的错误,并将第一个符合该类型的错误赋值给目标变量
func As(err error, target any) bool
err
是需要检查的错误;target
是一个指向目标类型的指针,用于接收匹配到的错误。
errors.As
会递归地检查err
错误链中的每一层错误.- 如果找到一个错误的类型与
target
的类型匹配,则将该错误赋值给target
并返回true
. - 如果
err
实现了As
方法,则调用该方法进行处理 使用例
package main
import (
"errors"
"fmt"
)
type TypicalErr struct {
e string
}
func (t TypicalErr) Error() string {
return t.e
}
func main() {
err := TypicalErr{"typical error"}
err1 := fmt.Errorf("wrap err: %w", err)
err2 := fmt.Errorf("wrap err1: %w", err1)
var e TypicalErr
if errors.As(err2, &e) {
fmt.Println("TypicalErr is on the chain of err2")
fmt.Println(err == e) // true
} else {
fmt.Println("TypicalErr is not on the chain of err2")
}
}
并发
Goroutines
- Go 中的并发执行单位,类似于轻量级的线程。
- Goroutine 的调度由 Go 运行时管理,用户无需手动分配线程。
- 使用
go
关键字启动 Goroutine。 - Goroutine 是非阻塞的,可以高效地运行成千上万个 Goroutine。 创建一个Goroutines的语法:
go myFunction()
channels
- Go 中用于在 Goroutine 之间通信的机制。
- 支持同步和数据共享,避免了显式的锁机制。
- 使用
chan
关键字创建,通过<-
操作符发送和接收数据。没有->
只有<-
使用例
package main
import (
"fmt"
)
func main() {
// 创建一个无缓冲的 Channel,类型为 int
ch := make(chan int)
// 开启一个 goroutine,将数据发送到 Channel 中
go func() {
ch <- 42 // 发送数据
}()
// 从 Channel 中接收数据
value := <-ch
fmt.Println("Received:", value)
}
创建Channel时可以指定缓冲区大小:
ch := make(chan int,100)
缓冲用例
package main
import "fmt"
func main() {
// 这里我们定义了一个可以存储整数类型的带缓冲通道
// 缓冲区大小为2
ch := make(chan int, 2)
// 因为 ch 是带缓冲的通道,我们可以同时发送两个数据
// 而不用立刻需要去同步读取数据
ch <- 1
ch <- 2
// 获取这两个数据
fmt.Println(<-ch)
fmt.Println(<-ch)
}
select
select
语句使得一个 goroutine 可以等待多个通信操作。select
会阻塞,直到其中的某个 case 可以继续执行:
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
WaitGroup
sync.WaitGroup
是 Go 语言 sync
包中提供的一个同步原语,用于等待一组并发操作的完成。它通常用于确保在所有启动的 Goroutine 完成它们的任务之前,主 Goroutine 不会提前退出。WaitGroup
通过计数器来实现这一功能,计数器的值表示需要等待的 Goroutine 数量。
主要方法:
Add(delta int)
:将计数器的值增加delta
。通常在启动 Goroutine 之前调用,传入的delta
为 Goroutine 的数量.Done()
:将计数器的值减少 1。通常在 Goroutine 完成其任务后调用.Wait()
:阻塞调用者,直到计数器的值为 0。通常在主 Goroutine 中调用,用于等待所有 Goroutine 完成.
用例:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // 确保在函数结束时调用 Done
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second) // 模拟耗时操作
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
// 启动 3 个 Goroutine
for i := 1; i <= 3; i++ {
wg.Add(1) // 每启动一个 Goroutine,计数器加 1
go worker(i, &wg)
}
// 等待所有 Goroutine 完成
wg.Wait()
fmt.Println("All workers done")
}
Gin
什么是Gin? Gin是一个使用Go语言开发的Web框架。 它提供类似Martini的API,但性能更佳,速度提升高达40倍。 如果你是性能和高效的追求者, 你会爱上 Gin。
截止25.1.8 Gin已获得79.8k star,是目前最流行的Golang web框架
安装
mkdir一个你要干大事的文件夹并cd进去 新建一个go模块
go mod init gin
安装框架
go get github.com/gin-gonic/gin
一下是官方文档给出的示例项目,将它保存到 main.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
var db = make(map[string]string)
func setupRouter() *gin.Engine {
// Disable Console Color
// gin.DisableConsoleColor()
r := gin.Default()
// Ping test
r.GET("/ping", func(c *gin.Context) {
c.String(http.StatusOK, "pong")
})
// Get user value
r.GET("/user/:name", func(c *gin.Context) {
user := c.Params.ByName("name")
value, ok := db[user]
if ok {
c.JSON(http.StatusOK, gin.H{"user": user, "value": value})
} else {
c.JSON(http.StatusOK, gin.H{"user": user, "status": "no value"})
}
})
// Authorized group (uses gin.BasicAuth() middleware)
// Same than:
// authorized := r.Group("/")
// authorized.Use(gin.BasicAuth(gin.Credentials{
// "foo": "bar",
// "manu": "123",
//}))
authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
"foo": "bar", // user:foo password:bar
"manu": "123", // user:manu password:123
}))
/* example curl for /admin with basicauth header
Zm9vOmJhcg== is base64("foo:bar")
curl -X POST \
http://localhost:8080/admin \
-H 'authorization: Basic Zm9vOmJhcg==' \
-H 'content-type: application/json' \
-d '{"value":"bar"}'
*/
authorized.POST("admin", func(c *gin.Context) {
user := c.MustGet(gin.AuthUserKey).(string)
// Parse JSON
var json struct {
Value string `json:"value" binding:"required"`
}
if c.Bind(&json) == nil {
db[user] = json.Value
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
})
return r
}
func main() {
r := setupRouter()
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}
运行 go run main.go
即可在访问 ~~好了你已经知道怎么写网页了,接下来做个后端8( ̄︶ ̄)↗ ~~ 官方文档提供了丰富的功能实例 示例 | Gin Web Framework
之后就用goland开发了
附
数字数据类型
序号 | 类型和描述 |
---|---|
1 | uint8 无符号 8 位整型 (0 到 255) |
2 | uint16 无符号 16 位整型 (0 到 65535) |
3 | uint32 无符号 32 位整型 (0 到 4294967295) |
4 | uint64 无符号 64 位整型 (0 到 18446744073709551615) |
5 | int8 有符号 8 位整型 (-128 到 127) |
6 | int16 有符号 16 位整型 (-32768 到 32767) |
7 | int32 有符号 32 位整型 (-2147483648 到 2147483647) |
8 | int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
Links
工具 & 高质量文
- https://www.runoob.com/go/go-interfaces.html
- https://geektutu.com/post/quick-go-gin.html
- geektutu/7days-golang: 7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列
- GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly. 这是用来链接数据库的,提供了增删查改之类的方法
- Go-web开发快速入门——二、使用jwt配合中间件进行用户认证(附源码,超详细)_go实现中间件鉴权授权-CSDN博客
- Go-web开发快速入门——一、gin+gorm完成用户注册登录及用数据库存储用户信息(附源码,超详细)_gorm gin-CSDN博客
- https://www.topgoer.com/gin%E6%A1%86%E6%9E%B6/%E7%AE%80%E4%BB%8B.html