第01回 转生到了只用 Golang 的世界

我揉了揉眼睛,发现自己站在一个明亮的编程大厅,周围全是敲键盘的声音。昨天还在熬夜调试 C++ 的内存泄漏,今天却穿越到了一个奇怪的世界——这里每个人都在用一种叫 Golang 的语言编程,连路边的广告牌上都写着 “用 Golang 改变世界”。

“新来的,写个程序试试吧,”一个戴眼镜的导师走过来,递给我一台电脑,“先写个函数,打印‘Hello, World!’。”

好吧,我是 C++ 老手,这应该简单。我习惯性地写:

 #include <iostream>
 
 int main() 
 {
     std::cout << "Hello, World!" << std::endl;
     return 0;
 }

编译器报错,提示“未知命令 #include”。我愣住了,这里没有 C++?导师冷冷地说:“这里只有 Golang,C++ 在这个世界已经消失了。”

我只好硬着头皮改成 Golang 风格,回忆着写:

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

编译又报错:“expected declaration, found '{'”。我抓狂了,C++ 里函数的左花括号 { 可以换行写啊!导师叹气说:“Golang 强制要求左花括号必须和函数名在同一行,不然编译器不认。”

我改成:

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

这次编译通过了,但导师皱眉:“你干嘛加分号?Golang 语句末尾不用分号,C++ 的习惯害了你。”我尴尬地发现,C++ 里每个语句后面都要加 ;,但这里多余的分号虽然不报错,却显得很奇怪。

我决定查查 Golang 和 C++ 的区别,打开这个世界的搜索引擎,输入“Golang vs C++”。结果显示,Golang 的语法更简洁,函数定义必须 { 同行,分号自动处理。我记下了:Golang 强制 { 同行,末尾不用 ;

接下来,我试着导入包。C++ 用 #include,Golang 用 import,我写:

 import "fmt"
 import "os"

导师又摇头:“可以,但最好用括号包裹,写成:

 import (
     "fmt"
     "os"
 )

这样更整齐。”我点点头,感觉 Golang 有点像在强迫我改掉 C++ 的坏习惯。

然后,我要定义变量。C++ 里我写 int a = 5;,Golang 呢?我先试试 var a int = 5,编译通过。但导师说:“函数里用 a := 5 更好,自动推导类型。”我试了,确实简洁,但总觉得少了点 C++ 里明确类型的安全感。

我好奇 a 的类型是什么,C++ 里用 typeid(a).name(),Golang 怎么查?导师教我用 fmt.Fprintf(os.Stdout, "%T", a),比如:

 a := 5
 fmt.Fprintf(os.Stdout, "Type of a is %T\n", a) // 输出 "Type of a is int"

这比 C++ 的方式更直观,我记住了。

定义多个变量时,我习惯 C++ 的 int a, b;,Golang 呢?我写 var a, b int,单行可以;也可以多行:

 var (
     a int
     b int
 )

我试了试,感觉灵活,但一开始老是忘了一行定义多个变量的语法。

最后,导师让我定义枚举。C++ 里我用 enum Color { Red, Green, Blue };,Golang 没有 enum,怎么办?导师说用 constiota,比如:

 const (
     Red = iota   // 0
     Green        // 1
     Blue         // 2
 )

iota 自动递增,我觉得很聪明,但也觉得比 C++ 的 enum 抽象,适应起来费劲。

就这样,第一天在 Golang 世界,我犯了无数错,但也学到了不少。C++ 的习惯让我处处碰壁,但这个世界逼着我改变,我决定继续探索。


调查笔记:转生成为 Golang 工程师的第一回详解

本文旨在以轻小说风格的第一人称叙述,总结我在学习 Golang 的第一回,重点涵盖以下知识点:函数左花括号与函数名同行、语句末尾无需分号、用括号包裹导入包、在函数内优先用 := 定义变量、查询变量类型、单行和多行定义多个变量、用 constiota 定义枚举类型。以下为详细分析和背景信息,适合有 C++ 背景的初学者深入理解。

故事背景与情节设计

故事设定在一个以 Golang 为主流语言的世界,我作为一名 C++ 程序员“转生”到此,面临学习 Golang 的挑战。第一回的剧情围绕我在编程大厅中完成导师布置的任务,逐步掌握 Golang 的基础语法。

知识点详解

  1. 函数左花括号必须与函数名同行
    在 C++ 中,函数的左花括号 { 可以放在下一行(K&R 风格)或同一行(Allman 风格),但 Golang 强制要求 { 与函数名在同一行。这是 Golang 格式化工具 gofmt 的规范,违反此规则会导致编译错误。例如:

     func helloWorld() { // 正确
         fmt.Println("Hello, World!")
     }
     func helloWorld()  // 错误,{ 必须同行
     {
         fmt.Println("Hello, World!")
     }
    

    这与 C++ 的灵活性不同,旨在统一代码风格,减少歧义。对于有 C++ 背景的我来说,这是个不小的适应挑战,总是想把 { 放下一行,结果编译老是报错。

  2. 语句末尾无需分号
    C++ 要求每条语句以分号结尾,而 Golang 自动在行尾插入分号(基于语法规则),因此通常无需手动添加分号。例如:

     fmt.Println("Hello, World!") // 正确,无需分号
     fmt.Println("Hello, World!"); // 也可,但不推荐,增加冗余
    

    这简化了代码编写,但需要注意,如果在一行写多条语句,则用分号分隔。来自 C++ 的我,习惯了每个语句后面加 ;,一开始老是多加,结果发现 Golang 编译器并不强制,但导师建议省略,省得代码看起来杂乱。

  3. 导入的包可以用括号包裹
    Golang 的导入语句支持用括号包裹多个包,增强可读性,尤其在导入多个包时。例如:

     import (
         "fmt"
         "os"
     )
    

    与 C++ 的 #include <iostream> 不同,Golang 的导入是模块化的,括号方式更适合组织复杂的依赖。我一开始没注意,直接写 import "fmt",后来看到别人用括号包裹,觉得更整齐,试着用了,确实方便。

  4. 使用 var 定义变量,但在函数内更推荐 :=
    Golang 提供 var 关键字定义变量,类似于 C++ 的 int a;,例如:

     var a int = 5
    

    但在函数内部,推荐使用短声明 :=,它会自动推导类型,简化代码。例如:

     func main() {
         a := 5 // 自动推导为 int
         b := "hello" // 自动推导为 string
     }
    

    := 只能在函数内使用,var 则适用于全局变量或需要明确类型的场景。来自 C++ 的我,习惯了明确写类型,比如 int a = 5;,一开始用 var a int = 5 觉得安全,但导师说函数里用 a := 5 更简洁,我试了试,确实省事,但总觉得少了点“控制感”。

  5. 如何查询变量类型
    C++ 中可以用 typeid(a).name() 获取变量类型,Golang 没有直接的等价方法,但可以通过 fmt.Fprintf%T 格式化输出类型。例如:

     import "fmt"
     import "os"
     
     func main() {
         a := 5
         fmt.Fprintf(os.Stdout, "Type of a is %T\n", a) // 输出 "Type of a is int"
     }
    

    或者使用 reflect.TypeOf 获取更详细的类型信息,但对于初学者,%T 更直观。我一开始不知道怎么查类型,导师提示用 fmt.Fprintf,试了试,觉得挺实用,尤其调试时能快速确认类型。

  6. 分别用单行和多行的方式定义多个变量
    Golang 支持单行和多行定义多个变量,灵活性高。例如:

    • 单行方式:

       var a, b int = 1, 2 // 明确类型
       c, d := 3, 4 // 函数内,自动推导
      
    • 多行方式:

       var (
           a int
           b int
       )
      

      或:

       var a int
       var b int
      

      这与 C++ 的 int a, b; 类似,但 Golang 的多行方式更适合复杂场景。我一开始老是写成 var a int; var b int;,导师说可以省略分号,还可以多行写,试了试,觉得多行写更清晰,但单行写也挺快。

  7. 使用 const 定义枚举类型,以及 iota 的用法
    C++ 中用 enum 定义枚举,Golang 没有直接的 enum,但可以用 constiota 实现类似功能。iota 是 Golang 的常量计数器,从 0 开始自动递增。例如:

     const (
         Red = iota   // 0
         Green        // 1
         Blue         // 2
     )
    

    这与 C++ 的 enum Color { Red, Green, Blue }; 功能类似,但 iota 更灵活,可以跳过值或自定义。例如:

     const (
         Sunday = iota
         Monday
         Tuesday
         _        // 跳过 3
         Thursday // 从 4 开始
     )
    

    我一开始用 C++ 的思维想写 enum,结果发现 Golang 没有,直接用 constiota,觉得挺新奇,但也觉得比 enum 抽象了点,适应起来有点费劲。

对比与适应

对于有 C++ 背景的读者,这些差异可能需要时间适应。例如,函数花括号的强制同行规范可能让习惯 K&R 风格的程序员感到不适,而 := 的引入则简化了函数内变量声明。iota 的使用则提供了一种优雅的枚举定义方式,减少了手动赋值的麻烦。

总结与展望

通过第一回的学习,我初步掌握了 Golang 的基础语法,包括函数定义、变量声明和常量枚举。这些知识点为后续深入学习并发、接口等高级特性奠定了基础。下一回,我将探索更多 Golang 的独特设计,期待更多惊喜!

关键引文

The best code is no code at all.