Deprecated: Constant PDO::MYSQL_ATTR_USE_BUFFERED_QUERY is deprecated since 8.5, use Pdo\Mysql::ATTR_USE_BUFFERED_QUERY instead in /www/wwwroot/www.1998123.xyz/var/Typecho/Db/Adapter/Pdo/Mysql.php on line 71
分类 go 下的文章 - 98123_学习与记录

分类 go 下的文章

很好!既然你有 Java 背景,我会通过对比的方式帮你快速上手 Go。我会展示一些常见场景的 Java 和 Go 代码对比。

1. Hello World & 基本结构

Java:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Go:

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

关键差异:

  • Go 没有类,函数可以独立存在
  • package main 是可执行程序的入口包
  • 不需要分号(可选)
  • 首字母大写表示公开(public),小写表示私有

2. 变量声明与类型

Java:

public class Variables {
    public static void main(String[] args) {
        // 显式类型
        String name = "Alice";
        int age = 25;
        double salary = 50000.50;
        boolean isActive = true;
        
        // 类型推断 (Java 10+)
        var city = "Taipei";
        
        // 常量
        final int MAX_SIZE = 100;
    }
}

Go:

package main

func main() {
    // 显式类型
    var name string = "Alice"
    var age int = 25
    var salary float64 = 50000.50
    var isActive bool = true
    
    // 类型推断
    var city = "Taipei"
    
    // 短声明(最常用)
    country := "Taiwan"
    
    // 常量
    const MaxSize = 100
}

关键差异:

  • Go 的 := 是最常用的声明方式
  • Go 没有隐式类型转换,必须显式转换
  • 类型写在变量名后面

3. 结构体 vs 类

Java:

public class Person {
    private String name;
    private int age;
    
    // 构造函数
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Getter
    public String getName() {
        return name;
    }
    
    // 方法
    public void introduce() {
        System.out.println("I'm " + name + ", " + age + " years old");
    }
}

// 使用
Person p = new Person("Bob", 30);
p.introduce();

Go:

package main

import "fmt"

// 结构体定义
type Person struct {
    Name string  // 大写=公开
    age  int     // 小写=私有
}

// "构造函数"(惯例)
func NewPerson(name string, age int) *Person {
    return &Person{
        Name: name,
        age:  age,
    }
}

// 方法(接收者)
func (p *Person) Introduce() {
    fmt.Printf("I'm %s, %d years old\n", p.Name, p.age)
}

func main() {
    p := NewPerson("Bob", 30)
    p.Introduce()
}

关键差异:

  • Go 没有类,用结构体 + 方法
  • 没有构造函数,通常用 NewXxx 函数
  • 方法通过接收者(receiver)绑定到类型上
  • 没有 this/self,用接收者变量名

4. 接口

Java:

public interface Speaker {
    void speak();
}

public class Dog implements Speaker {
    @Override
    public void speak() {
        System.out.println("Woof!");
    }
}

public class Cat implements Speaker {
    @Override
    public void speak() {
        System.out.println("Meow!");
    }
}

// 使用
Speaker dog = new Dog();
dog.speak();

Go:

package main

import "fmt"

// 接口定义
type Speaker interface {
    Speak()
}

// Dog 类型
type Dog struct{}

func (d Dog) Speak() {
    fmt.Println("Woof!")
}

// Cat 类型
type Cat struct{}

func (c Cat) Speak() {
    fmt.Println("Meow!")
}

func main() {
    var s Speaker
    
    s = Dog{}
    s.Speak()
    
    s = Cat{}
    s.Speak()
}

关键差异:

  • Go 的接口是隐式实现(duck typing)
  • 不需要 implements 关键字
  • 只要实现了接口的所有方法就自动满足接口

5. 错误处理

Java:

public class ErrorHandling {
    public static int divide(int a, int b) throws ArithmeticException {
        if (b == 0) {
            throw new ArithmeticException("Division by zero");
        }
        return a / b;
    }
    
    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

Go:

package main

import (
    "errors"
    "fmt"
)

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println(result)
}

关键差异:

  • Go 没有异常(exceptions)
  • 错误作为返回值返回(通常是最后一个返回值)
  • 使用 if err != nil 检查错误
  • nil 表示没有错误

6. 集合操作

Java:

import java.util.*;

public class Collections {
    public static void main(String[] args) {
        // List
        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("banana");
        
        // Map
        Map<String, Integer> ages = new HashMap<>();
        ages.put("Alice", 25);
        ages.put("Bob", 30);
        
        // 遍历
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        
        for (Map.Entry<String, Integer> entry : ages.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

Go:

package main

import "fmt"

func main() {
    // Slice (动态数组)
    fruits := []string{"apple", "banana"}
    fruits = append(fruits, "orange")
    
    // Map
    ages := make(map[string]int)
    ages["Alice"] = 25
    ages["Bob"] = 30
    
    // 或者字面量初始化
    ages2 := map[string]int{
        "Alice": 25,
        "Bob":   30,
    }
    
    // 遍历 slice
    for i, fruit := range fruits {
        fmt.Printf("%d: %s\n", i, fruit)
    }
    
    // 遍历 map
    for name, age := range ages2 {
        fmt.Printf("%s: %d\n", name, age)
    }
}

关键差异:

  • Go 的 slice 类似 ArrayList,但更底层
  • range 用于遍历,返回索引/键和值
  • _ 忽略不需要的返回值

7. 并发

Java:

public class Concurrency {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Thread 1: " + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Thread 2: " + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        t1.start();
        t2.start();
        
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Go:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup
    
    wg.Add(2)
    
    // Goroutine 1
    go func() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            fmt.Println("Goroutine 1:", i)
            time.Sleep(100 * time.Millisecond)
        }
    }()
    
    // Goroutine 2
    go func() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            fmt.Println("Goroutine 2:", i)
            time.Sleep(100 * time.Millisecond)
        }
    }()
    
    wg.Wait()
}

关键差异:

  • go 关键字启动 goroutine(轻量级线程)
  • WaitGroup 等待 goroutine 完成
  • Go 的并发模型更简单、更轻量

8. Channel 通信(Go 特色)

Go 的 channel 是线程安全的通信机制,这是 Java 没有的内置特性:

package main

import "fmt"

func main() {
    // 创建 channel
    messages := make(chan string)
    
    // 发送数据到 channel
    go func() {
        messages <- "Hello"
        messages <- "World"
        close(messages)
    }()
    
    // 从 channel 接收数据
    for msg := range messages {
        fmt.Println(msg)
    }
}

快速学习建议

  1. 先掌握基础:变量、控制流、函数、结构体
  2. 理解指针:Go 有指针但比 C 简单,没有指针运算
  3. 接口的隐式实现:这是 Go 最优雅的特性之一
  4. 错误处理模式:习惯 if err != nil
  5. 并发编程:goroutine 和 channel 是 Go 的杀手级特性

推荐资源

ZincSearch轻量级全文搜索引擎入门到
Zinc是一个用于对文档进行全文搜索的搜索引擎。它是开源的,内置在 Go 中。Zinc不是从头开始构建索引引擎,而是构建在 bluge 之上,这是一个出色的索引库。ZincSearch特点:

无模式索引
资源利用率低
易于使用的轻量级 GUI
内置身份验证
用于编程使用的简单 API
与希望从 Elasticsearch 迁移到 Zinc 的应用程序兼容的 Elasticsearch API(摄取 - 单记录和批量 API)。
2022年5月31日,已经实现基本搜索和API了,集群高可用分布式等等还在开发中。
github:https://github.com/zinclabs/zinc
官网:https://zincsearch.com/

安装
下载window版的易于上手: https://github.com/zinclabs/zinc/releases

set ZINC_FIRST_ADMIN_USER=admin
set ZINC_FIRST_ADMIN_PASSWORD=admin
mkdir data
zinc.exe

登录

然后根据上面设置的密码登录 :http://localhost:4080/

go module 的目的是依赖管理,所以使用 go module 时你可以舍弃 go get 命令(但是不是禁止使用, 如果要指定包的版本或更新包可使用go get,平时没有必要使用)

因go的网络问题, 所以推荐使用 goproxy.cn设置

// 阿里云镜像
GOPROXY=https://mirrors.aliyun.com/goproxy/
// 中国golang镜像
GOPROXY=https://goproxy.io
// 七牛云为中国的gopher提供了一个免费合法的代理goproxy.cn,其已经开源。只需一条简单命令就可以使用该代理:

go env -w GOPROXY=https://goproxy.cn,direct

设置GO111MODULE环境变量

要使用go module 首先要设置GO111MODULE=on,GO111MODULE 有三个值,off、on、auto,off 和 on 即关闭和开启,auto 则会根据当前目录下是否有 go.mod 文件来判断是否使用 modules 功能。无论使用哪种模式,module 功能默认不在 GOPATH 目录下查找依赖文件,所以使用 modules 功能时请设置好代理。
在使用 go module 时,将 GO111MODULE 全局环境变量设置为 off,在需要使用的时候再开启,避免在已有项目中意外引入 go module。

windows:

   set GO111MODULE=on

mac:

export GO111MODULE=on

然后输入

go env

查看 GO111MODULE 选项为 on 代表修改成功