net/http 包的基本用法
· 阅读需 1 分钟
基本用法:
- 创建 HTTP 服 务器
- 处理 HTTP 请求,POST、GET
- 定义路由和处理器函数
- 启动服务器监听端口
基本用法:
- 创建 HTTP 服 务器
- 处理 HTTP 请求,POST、GET
- 定义路由和处理器函数
- 启动服务器监听端口
Go使用特定时间戳(2006-01-02 15:04:05)作为布局字符串:
t := time.Now()
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2023-10-08 14:30:45
fmt.Println(t.Format("2006/01/02 15:04:05")) // 2023/10/08 14:30:45
fmt.Println(t.Format("2006.01.02 15:04:05")) // 2023.10.08 14:30:45
fmt.Println(t.Format("2006年01月02日 15时04分05秒")) // 2023年10月08日 14时30分45秒
Go内置多种标准格式,直接使用time包常量:
fmt.Println(time.Now().Format(time.RFC3339)) // 2023-10-08T14:30:45+08:00
fmt.Println(time.Now().Format(time.RFC1123)) // Mon, 08 Oct 2023 14:30:45 CST
处理无分隔符的日期字符串时需注意布局字符串格式:
func parseYearMonth(str string) (int, time.Month) {
t, err := time.Parse("200601", str) // 布局字符串必须使用"200601"
if err != nil {
log.Fatal("解析失败:", err)
}
return t.Year(), t.Month()
}
// 使用示例
year, month := parseYearMonth("202310")
fmt.Printf("%d年%s月", year, month) // 2023年October月
= 赋值操作符var a int
a = 100
:= 短变量声明a := 100
a,b := 200,300
func closureDemo(){
for i:=0; i< 3;i++ {
go func(){
fmt.Print(i," ") // 闭包
}()
}
}
这段代码可能会输出 3 3 3,因为 i 是在闭包外部定义的变量,所有的 goroutine 都共享同一个 i 变量。
func closureDemo(){
for i:=0; i< 3;i++ {
val :=i
go func(){
fmt.Print(val," ")
}()
}
}
使用局部变量可以避免闭包带来的问题。每次循环都会创建一个新的变量。
i 变量定义在堆中,val 变量定义在栈中。
func closureDemo(){
for i:=0; i< 3;i++ {
go func(v int){
fmt.Print(v," ")
}(i)
}
}
通过参数将 i 的值传递给闭包函数,确保每个 goroutine 都有自己的 i 值。
func main() {
var counter *int64 = new(int64)
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func(v *int64) {
*v += 1
wg.Done()
}(counter)
}
wg.Wait()
fmt.Println("Counter:", *counter)
}
输出的值小于 1000
func concurrentAssignment() {
var counter int64
var wg sync.WaitGroup
// 使用原子操作保证并发安全
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
atomic.AddInt64(&counter, 1) // 使用=修改共享变量
wg.Done()
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
// 使用通道安全传递值
ch := make(chan int)
go func() {
val := <-ch // 使用:=接收新值
fmt.Println("Received:", val)
}()
ch <- 42 // 使用=发送值
}
使用 atomic.AddInt64 来实现原子操作,确保在并发环境下对 counter 的安全修改。
type User struct {
ID int
Name string
}
使用 & 符号直接创建结构体指针,并初始化字段. 推荐使用
优点:
u := &User{
ID: 1,
Name: "Alice",
}
// 1. 分配内存,返回一个指向零值的指针
u := new(User)
// 2. 手动赋值字段
u.ID = 1
u.Name = "Alice"
user := &User{2, "Alice"}
缺点:
类型断言用于检查接口值的动态类型是否符合某个特定类型。
value, ok := interfaceVar.(ConcreteType)
interfaceVar 是一个接口变量ConcreteType 是你想要断言的具体类型value 是断言成功后转换的值ok 是一个布尔值,表示断言是否成功var writer io.Writer = os.Stdout
if closer, ok := writer.(io.Closer); ok {
closer.Close() // 安全调用接口扩展方法
}
// 直接转换(失败时触发panic)
str := anyVar.(string)
var v interface{} = 42
// 基础类型匹配
_, ok1 := v.(int) // ok1 = true
_, ok2 := v.(string) // ok2 = false
// 接口类型匹配
_, ok3 := v.(fmt.Stringer) // 检查是否实现特定接口
.(type) 必须与 switch 一起使用。
switch v := err.(type) {
case *AppError:
// 处理自定义错误类型
case *os.PathError:
// 处理系统路径错误
case nil:
// 没有错误的情况
default:
// 未知错误类型
}