2024-08-07

为了配置Go中国镜像代理服务,你需要设置环境变量GOPROXY。以下是如何设置的示例代码:




# 设置GOPROXY环境变量
export GOPROXY=https://goproxy.cn,direct
 
# 验证设置是否成功
go env GOPROXY

在你的操作系统中打开终端或命令行界面,并输入上述命令。这会将Go模块代理设置为goproxy.cn,并且如果该代理无法使用,则会直接访问模块内容。

如果你使用的是Windows系统,可以使用以下命令来设置环境变量:




:: 设置GOPROXY环境变量
setx GOPROXY https://goproxy.cn,direct
 
:: 验证设置是否成功
go env GOPROXY

请注意,这些命令只在当前终端会话中设置环境变量。要永久设置环境变量,你需要在系统的环境变量设置中进行配置。

2024-08-07

TRPC是一个基于Go的高性能RPC框架,它提供了代码生成、路由、中间件等功能。以下是一个简单的TRPC示例,展示了如何定义服务、创建服务器以及调用服务。

首先,你需要安装TRPC:




go get github.com/cs3238-2021/go-trpc

定义服务:




// hello.proto
syntax = "proto3";
 
package pb;
 
service Hello {
  rpc Hello(HelloRequest) returns (HelloResponse);
}
 
message HelloRequest {
  string name = 1;
}
 
message HelloResponse {
  string message = 1;
}

生成Go代码:




trpc-go-gen -in hello.proto -out .

实现服务:




package main
 
import (
    "context"
    "fmt"
    "github.com/cs3238-2021/go-trpc/examples/helloworld/pb"
)
 
type helloService struct{}
 
func (h *helloService) Hello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
    return &pb.HelloResponse{Message: "Hello, " + req.Name + "!"}, nil
}
 
func main() {
    server := trpc.NewServer()
    server.Register(new(helloService))
    // ... start the server
}

启动服务并调用服务:




package main
 
import (
    "context"
    "fmt"
    "log"
    "net"
 
    "github.com/cs3238-2021/go-trpc/examples/helloworld/pb"
)
 
func main() {
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }
    defer listener.Close()
 
    server := trpc.NewServer()
    server.Register(new(helloService))
 
    go func() {
        if err := server.Serve(listener); err != nil {
            log.Fatal(err)
        }
    }()
 
    client := trpc.NewClient(listener.Addr().String())
    resp, err := client.Call(context.Background(), &pb.HelloRequest{Name: "World"})
    if err != nil {
        log.Fatal(err)
    }
 
    fmt.Println(resp.(*pb.HelloResponse).Message)
}

以上代码展示了如何定义一个RPC服务,如何实现它,以及如何启动服务器并从客户端调用该服务。这个例子是基于一个简单的“Hello World”服务,但TRPC可以用于更复杂的应用程序。

2024-08-07

context包提供了管理并发操作中的取消信号、超时值、键值对等上下文数据的机制。

概述

context包中的Context接口提供了以下方法:

  • Deadline() (deadline time.Time, ok bool): 返回上下文被取消的截止日期。
  • Done() <-chan struct{}: 返回一个channel,当上下文被取消时,该channel会关闭。
  • Err() error: 返回导致上下文被取消的原因。
  • Value(key interface{}) interface{}: 返回与上下文关联的键值对。

使用示例

创建带有超时的上下文:




ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
 
// 使用ctx进行操作...

在goroutine中处理超时:




ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
 
go func() {
    select {
    case <-ctx.Done():
        fmt.Println("超时或上下文被取消,退出goroutine。")
        return
    case <-time.After(20 * time.Second):
        fmt.Println("goroutine运行时间超过预定上下文时间。")
    }
}()
 
// 执行其他任务...

在HTTP服务中使用上下文传递请求范围的值:




func MyHandler(w http.ResponseWriter, r *http.Request) {
    ctx := context.WithValue(r.Context(), "key", "value")
    go HandleRequest(ctx)
}
 
func HandleRequest(ctx context.Context) {
    value := ctx.Value("key")
    // 处理value...
}

以上代码展示了如何在Go语言中使用context包来管理并发操作的上下文,包括创建带有超时和取消功能的上下文、在goroutine中响应上下文的取消信号、在HTTP服务中传递带有键值对的上下文数据。

2024-08-07

Go语言是一门现代的、静态类型的编译型语言,它的设计目标是简洁、快速编译、并行处理、内存安全、高效并发执行。以下是Go语言的一些核心知识点:

  1. 简洁的语法:Go语言的语法非常简洁,学习起来相对容易。
  2. 静态类型检查:Go语言是静态类型的语言,意味着所有变量在编译时就必须确定其类型。
  3. 并发编程:Go语言内置了goroutine的概念,可以非常简单的编写并发程序。
  4. 内存管理:Go语言自动进行内存管理,你不需要手动删除不再使用的内存。
  5. 编译速度快:Go语言编译速度非常快,可以快速的进行开发和测试。
  6. 标准库丰富:Go语言有一个非常丰富的标准库,提供了很多现成的工具可以使用。
  7. 性能优秀:Go语言的性能也很优秀,尤其是在网络编程和多核并行处理上。
  8. 编译成机器码:Go语言编译后的程序是机器码,所以它可以跳过解释器层,直接执行。
  9. 语言设计的理念:简洁、明确、安全、并发。

Go语言的核心知识点还有很多,例如指针、结构体、接口、错误处理、切片(slices)和映射(maps)等。

以下是一个简单的Go程序示例,它定义了一个函数,该函数计算并返回两个整数的和:




package main
 
import "fmt"
 
func add(a int, b int) int {
    return a + b
}
 
func main() {
    fmt.Println(add(1, 2))
}

这个程序首先导入了fmt包,用于格式化输入/输出。然后定义了一个名为add的函数,该函数接受两个整数作为参数并返回它们的和。最后在main函数中调用add函数,并打印结果。

2024-08-07

在2024年,以下是Golang(Go)和Java在一些关键方面的比较:

  1. 内存管理:Go 使用自动垃圾回收(GC),而 Java 需要手动管理内存。
  2. 并发编程:Go 通过 goroutines 和 channels 提供了内置的并发支持,这比 Java 的线程和锁更易用。
  3. 运行时性能:Go 编译成机器码,因此它通常具有更高的性能。
  4. 生态系统:尽管 Java 拥有更成熟的库和框架,但 Go 的生态系统正在迅速发展。
  5. 类型安全:Go 是静态类型语言,提供了编译时的类型检查,而 Java 是动态类型语言。
  6. 学习曲线:Go 的学习曲线通常被认为更平滑,而 Java 需要更多的学习资源。

代码示例对比(简单的HTTP服务器):

Go:




package main
 
import (
    "fmt"
    "log"
    "net/http"
)
 
func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}
 
func main() {
    http.HandleFunc("/hello", helloHandler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Java (使用Spring Boot):




import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
 
@RestController
public class HelloController {
 
    @RequestMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }
}

在2024年,虽然 Java 在企业级应用、企业级框架和大型项目中占据主导地位,但 Go 因其并发性、性能和现代特性正在成为一种越来越受欢迎的选择。

2024-08-07

在使用VSCode编写Go语言时,可能会遇到以下几个大坑:

  1. 单元测试:Go语言的单元测试文件通常以 _test.go 结尾,在VSCode中,默认情况下,测试文件不会被识别和编译。解决方法是在 go.mod 文件所在目录打开VSCode,或者在VSCode设置中启用 "go.inferGopath": true
  2. goimportsgoimports 是Go语言的一个工具,用于格式化导入的包,并添加任何缺失的包。在VSCode中,可以通过安装Go插件并启用 go.useCodeSnippetsOnFunctionSuggest 选项来使用 goimports
  3. 研发4面真题解析:在VSCode中,可以通过安装Linux内核开发插件,并在 settings.json 中配置 "files.associations": {"*.ko": "linux-kernel-assembly"} 来提供Linux内核模块的语法高亮和缩进。

以下是解决这些问题的示例配置:




{
    "go.inferGopath": true,
    "go.useCodeSnippetsOnFunctionSuggest": true,
    "[linux-kernel-assembly]": {
        "editor.tabSize": 8
    },
    "files.associations": {
        "*.ko": "linux-kernel-assembly"
    }
}

请注意,具体配置可能会随着VSCode和Go插件的更新而变化,请根据实际情况调整配置。

2024-08-07



package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
func worker(id int, wg *sync.WaitGroup, jobs <-chan int, results chan<- int) {
    defer wg.Done() // 确保该协程结束时通知主协程
    for job := range jobs {
        // 模拟耗时工作
        fmt.Println("Worker", id, "started job", job)
        time.Sleep(time.Second)
        fmt.Println("Worker", id, "finished job", job)
 
        results <- job * 2 // 发送结果到results通道
    }
}
 
func main() {
    var wg sync.WaitGroup
    jobs := make(chan int, 100) // 创建一个缓冲为100的通道
    results := make(chan int, 100) // 创建一个缓冲为100的通道
 
    // 这里启动了4个工作协程
    for i := 1; i <= 4; i++ {
        wg.Add(1)
        go worker(i, &wg, jobs, results)
    }
 
    // 发送10个作业
    for j := 1; j <= 10; j++ {
        jobs <- j
    }
    close(jobs) // 关闭jobs通道,表示不会再有新的作业
 
    // 等待所有作业完成
    wg.Wait()
    close(results) // 所有作业完成后,关闭results通道
 
    // 打印结果
    for result := range results {
        fmt.Println(result)
    }
}

这段代码创建了一个工作池,其中有4个工作协程处理作业。主协程发送10个作业并关闭作业通道,工作协程处理完作业后,将结果发送到结果通道,并在所有作业处理完成后关闭结果通道。最后,主协程打印所有结果。这个例子展示了Go语言中协程和通道的基本使用方法,以及如何有效地进行并发任务处理。

2024-08-07

在 Go 语言中,map 是一种内置的数据类型,它可以存储任意类型的无序的键值对。

以下是 Go 语言中 Map 的一些常见操作:

  1. 声明 Map

声明一个 map 需要指定键和值的类型。这里,我们使用字符串作为键,整数作为值。




var map1 map[string]int
map1 = make(map[string]int)
  1. 向 Map 添加元素



map1["one"] = 1
map1["two"] = 2
map1["three"] = 3
  1. 从 Map 中删除元素



delete(map1, "one") // 删除键为 "one" 的元素
  1. 遍历 Map

Go 语言中遍历 map 的标准方法是使用 for-range 循环。




for key, value := range map1 {
    fmt.Printf("Key: %s, Value: %d\n", key, value)
}
  1. 检查 Map 中是否存在某个键

Go 语言中,我们可以通过判断该键是否存在来判断该键值对是否在 Map 中。




value, ok := map1["two"]
if ok {
    fmt.Printf("Key 'two' exists with value %d\n", value)
} else {
    fmt.Println("Key 'two' does not exist")
}
  1. 使用值类型为指针的 Map



var map2 map[string]*int
map2 = make(map[string]*int)
 
a := 1
map2["one"] = &a

以上就是 Go 语言中 Map 的一些基本操作。

2024-08-07



package main
 
import (
    "net/http"
    "github.com/gorilla/mux"
)
 
func main() {
    // 使用Gorilla的mux库来创建一个路由器
    router := mux.NewRouter().StrictSlash(true)
 
    // 定义路由处理函数
    router.HandleFunc("/", IndexHandler)
 
    // 启动服务器,监听在8080端口
    http.ListenAndServe(":8080", router)
}
 
// IndexHandler 是一个简单的HTTP处理函数,返回一个简单的响应
func IndexHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    w.Write([]byte("Hello, World!"))
}

这段代码创建了一个简单的Web服务器,使用了Gorilla的mux库来处理HTTP请求,并定义了一个路由处理函数IndexHandler来响应根路径(/)的GET请求。服务器运行在8080端口。这是学习Go语言和Web框架的一个很好的起点。

2024-08-07



package main
 
import (
    "fmt"
    "github.com/dgrijalva/jwt-go"
    "time"
)
 
// 定义一个Claims结构体用于存储JWT的相关信息
type CustomClaims struct {
    ID       int
    Username string
    jwt.StandardClaims
}
 
// 生成JWT token
func GenerateToken(id int, username string) (string, error) {
    // 创建Claims
    claims := CustomClaims{
        id,
        username,
        jwt.StandardClaims{
            ExpiresAt: time.Now().Add(time.Hour * 2).Unix(), // 设置过期时间
            Issuer:    "gin-jwt-example",                    // 签发者
        },
    }
 
    // 创建token
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 
    // 对token进行签名
    signedToken, err := token.SignedString([]byte("secret_key"))
    if err != nil {
        return "", err
    }
 
    return signedToken, nil
}
 
// 验证JWT token
func ValidateToken(tokenString string) (*CustomClaims, error) {
    token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
        return []byte("secret_key"), nil
    })
    if err != nil {
        return nil, err
    }
 
    if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
        return claims, nil
    }
 
    return nil, fmt.Errorf("invalid token")
}
 
func main() {
    // 生成token
    tokenString, err := GenerateToken(1, "user1")
    if err != nil {
        panic(err)
    }
    fmt.Printf("Generated Token: %s\n", tokenString)
 
    // 验证token
    claims, err := ValidateToken(tokenString)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Validated Token. ID: %d, Username: %s\n", claims.ID, claims.Username)
}

这段代码展示了如何在Go语言中使用jwt-go库生成和验证JWT token。首先定义了一个CustomClaims结构体来存储额外的信息,然后实现了生成和验证token的函数。最后,在main函数中演示了如何生成一个token并验证它。