当前位置:首页 > 技术分析 > 正文内容

Java程序员学Go语言指南(中篇)_java程序员自学

ruisui882个月前 (02-22)技术分析9

结构体革命:当类脱下铠甲

1. 类与结构体对比实验

// Java 类继承体系
class Animal {
    String name;
    public Animal(String name) { this.name = name; }
    void speak() { System.out.println("..."); }
}

class Dog extends Animal {
    public Dog(String name) { super(name); }
    @Override void speak() { System.out.println("汪汪!"); }
}
// Go 组合式实现
type Animal struct {
    name string
}

func (a *Animal) Speak() {
    fmt.Println("...")
}

type Dog struct {
    Animal // 嵌入代替继承
}

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

// 使用示例
dog := &Dog{Animal{"阿黄"}}
dog.Speak() // 输出:汪汪!

核心差异

  • Go放弃继承,拥抱组合
  • 方法定义与结构体解耦
  • 没有this关键字,显式声明接收器

2. 构造函数的秘密仪式

// Go工厂模式标准写法
type Config struct {
    timeout time.Duration
    retries int
}

// 推荐返回指针避免拷贝
func NewConfig(timeoutSec int) *Config {
    return &Config{
        timeout: time.Duration(timeoutSec)*time.Second,
        retries: 3, // 默认值
    }
}

// 使用方式 vs Java
cfg := NewConfig(5)  // Go
Config cfg = new Config(5); // Java

接口哲学:从契约到自由

1. 接口实现对比实验

// Java显式接口
interface Logger {
    void log(String message);
}

class FileLogger implements Logger { // 必须显式声明
    @Override
    public void log(String message) { /* 写入文件 */ }
}
// Go隐式接口
type Logger interface {
    Log(string)
}

type ConsoleLogger struct{} // 无需声明实现接口

func (c *ConsoleLogger) Log(msg string) { // 实现方法即自动满足
    fmt.Println(msg)
}

// 接口检测技巧(编译时验证)
var _ Logger = (*ConsoleLogger)(nil) // 确保实现完整性

2. 空接口的魔法

// 类似Java Object
func printAny(v interface{}) {
    switch x := v.(type) { // 类型断言
    case int:
        fmt.Printf("整数: %d\n", x)
    case string:
        fmt.Printf("字符串: %s\n", x)
    default:
        fmt.Printf("未知类型: %T\n", x)
    }
}

// 使用示例
printAny(42)        // 整数: 42
printAny("hello")   // 字符串: hello
printAny(3.14)      // 未知类型: float64

错误处理:从异常到返回值

1. 错误处理范式迁移

// Java异常处理
try {
    File file = new File("test.txt");
    BufferedReader br = new BufferedReader(new FileReader(file));
} catch (IOException e) {
    System.err.println("文件操作错误: " + e.getMessage());
} finally {
    br.close(); // 需要显式处理
}
// Go错误处理范式
f, err := os.Open("test.txt")
if err != nil {
    log.Fatalf("打开文件失败: %v", err)
}
defer f.Close() // 确保关闭

data := make([]byte, 1024)
count, err := f.Read(data)
if err != nil {
    if errors.Is(err, io.EOF) {
        fmt.Println("文件读取完毕")
    } else {
        log.Fatal("读取错误:", err)
    }
}

关键要点

  • defer实现资源自动释放(类似Java的try-with-resources)
  • 错误即普通值,通过多返回值传递
  • errors包提供错误处理工具链

包管理:从Maven到Go Module

1. 依赖管理对比



    
        com.google.code.gson
        gson
        2.8.9
    

// go.mod 文件示例
module myproject

go 1.20

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/stretchr/testify v1.8.4 // 间接依赖
)

replace github.com/old/pkg => ./local/pkg // 依赖重定向

2. 依赖管理操作对照表

操作

Maven命令

Go命令

初始化项目

mvn archetype:generate

go mod init

添加依赖

修改pom.xml

go get

更新依赖

mvn versions:update

go get -u

清理缓存

mvn clean

go clean -modcache

工程实践:从理论到战场

1. 项目结构规范

# 典型Go项目布局
├── cmd/           # 主程序入口
│   └── myapp/
├── internal/      # 私有代码(禁止外部引用)
│   └── service/
├── pkg/           # 公共库代码
│   └── utils/
├── go.mod
├── go.sum
└── Makefile       # 构建脚本

2. 单元测试对比

// JUnit测试示例
@Test
void testAdd() {
    assertEquals(4, Calculator.add(2, 2));
}
// Go测试示例
func TestAdd(t *testing.T) {
    got := Add(2, 2)
    want := 4
    if got != want {
        t.Errorf("期望 %d, 实际 %d", want, got)
    }
}

// 表格驱动测试
func TestMultiply(t *testing.T) {
    tests := []struct {
        a, b int
        want int
    }{
        {2, 3, 6},
        {-1, 5, -5},
        {0, 100, 0},
    }

    for _, tt := range tests {
        got := Multiply(tt.a, tt.b)
        if got != tt.want {
            t.Errorf("(%d * %d) 期望 %d, 实际 %d", 
                tt.a, tt.b, tt.want, got)
        }
    }
}

中篇实战项目

任务:构建用户管理系统原型

  1. 使用结构体定义用户模型(包含ID、姓名、邮箱)
  2. 实现用户存储接口(内存存储版)
  3. 编写HTTP接口:GET /users 获取用户列表POST /users 创建新用户
  4. 添加单元测试覆盖率 >70%

技术栈提示

  • Web框架:Gin(类似Spring Boot)
  • 测试框架:标准库testing + testify断言
  • 文档生成:swaggo(类似Swagger)

下篇剧透:我们将深入Go的并发模型,揭秘goroutine调度器的魔法,并对比Java线程池与Go并发模式的性能差异。最终通过实现高并发爬虫系统,体验Go的"并发即简单"哲学。

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/2166.html

标签: go swagger
分享给朋友:

“Java程序员学Go语言指南(中篇)_java程序员自学” 的相关文章

Beta版Linux Mint“Xia”发行版22.1发布

IT之家 12 月 13 日消息,Beta 版 Linux Mint“Xia” 22.1 昨日(12 月 12 日)发布,新版本基于 Ubuntu 24.04,内核版本为 Linux 6.8,长期支持将持续到 2029 年,为用户提供可靠稳定的使用体验。新版本在软件包管理方面,主要弃用了传统的 ap...

GitLab 14.6发布,优化Geo高可用,安全更新等

昨天,GitLab官方按照管理发布了有一个月度版本GitLab 14.6的发布,这也是本年度收官版本。14.6中在安全合规性方面,在Geo方面以及MD代码块一键复制等方便做了优化,另外还在UI图标方面发布了一套全新的图标。详细情况请和虫虫一起学习。GitLab 14.6主要改进使用 Geo 实现无缝...

美国民众负债累累 但今年假期消费者支出仍将创下新高

智通财经APP获悉,在迎接假期之际,许多美国人已经背负了创纪录的信用卡债务。然而,今年假期消费者支出仍将创下新高。根据美国零售联合会(NRF)上周发布的报告,预计今年11月1日至12月31日期间的消费总额将达到创纪录的9795亿至9890亿美元之间。NRF首席经济学家Jack Kleinhenz表示...

你感动了吗?佳能超规格镜头 RF 24-105mm F2.8深度测评

如果要你选一支用作多题材创作的挂机镜头,那我相信很多人会选择24-105mm这个焦段的镜头。作为一支可以实现从广角到长焦的变焦镜头,24-105mm有着丰富的焦段选择。只是基于镜头体积以及光学结构上的限制,此前的24-105mm镜头只能恒定在F4的光圈。而佳能打破了这一限制,将实用焦段和恒定光圈完美...

JavaScript数组操作:掌握常用方法,提升开发效率

JavaScript数组操作:从增删改查到高级应用本文深入解析JavaScript中常用的数组方法,包括push、unshift、pop、shift、map、filter、reverse、at 和 slice。通过详细的例子和应用场景,帮助开发者快速掌握这些方法,提升代码效率和可读性。开篇点题作为J...

Python中的11 种数组算法

1. 创建数组 创建数组意味着留出一个连续的内存块来存储相同类型的元素。在大多数语言中,您可以在创建数组时指定数组的大小。假设您正在书架上整理一组书籍,并且您需要为正好 10 本书预留空间。功能架上的每个空间都对应于数组中的一个索引。# Example in Python arr = [1, 2,...