笔者此前主要使用 Python 进行数据分析与脚本编写,近期出于学习需要开始接触 Go 语言。Python 的动态类型与极简语法很友好,而 Go 是编译型、静态类型的语言,二者在”怎么声明变量、怎么组织代码”上的思路差异很大。本笔记以 Python 为参照,把 Go 的核心语法逐条对照整理,方便像笔者一样从 Python 转过来的同学快速建立对应关系。
# Python defmain(): print("Hello") if __name__ == '__main__': main()
1 2 3 4 5 6 7 8
// Go package main
import"fmt"
funcmain() { fmt.Println("Hello") }
区别在于:Python 任何文件都可以”顶层直接跑代码”,而 Go 程序只能从 main 包下的 main() 函数开始执行。其它函数(比如 main1、main2)即使定义好了,不被调用就永远不会执行——这是 Go 新手最容易迷惑的一点。
二、导入 import
1 2 3 4
# Python import os from os import path import numpy as np
1 2 3 4 5 6 7 8 9 10 11
// Go 单个 import"fmt"
// Go 多个 import ( "fmt" "os" )
// Go 第三方包,路径要写全,代码里用最后一段作包名 import"github.com/gin-gonic/gin"// 代码里用 gin
关键差异:
Python 的 from xx import yy 可以直接用 yy;Go 没有这种写法,一律 包名.函数名 调用。
Go 里 import 了却没用到 → 编译报错 imported and not used: fmt。所以代码里删掉某功能时,记得同步删 import。
对应关系:Python 的 import os ≈ Go 的 import "os";numpy、pandas 这类第三方库,Go 里是 github.com/xxx/yyy 这样的完整路径。
三、变量声明
Python 里 x = 5 就行,声明这件事被隐藏了。Go 则必须显式声明,且有多种写法:
1 2 3 4 5
var age int = 15// ① 完整声明:var + 名字 + 类型 + 值 var score float64// ② 只声明类型,不赋值 → 得到"零值"0 score = 0.941// 之后单独赋值 name := "henny"// ③ 短声明 :=,类型由编译器推断,只能在函数体内用 var a = "RUNOOB"// ④ var 但省略类型,交给编译器推断(同 := 效果,但顶层也能用)
与 Python 的对应:
Python
Go
备注
x = 5
x := 5(函数内)或 var x = 5
Go 必须写明是声明
无此概念
var x int
只声明会得到零值,不是报错
无此概念
x := 5
简写,只能在函数体内
新手最容易踩的两个坑(笔者都踩了):
1 2 3 4 5 6 7 8 9 10
// 坑1:声明了但没使用 funcmain() { b := true// 声明了 // 但没有"读"过它 → 编译报错: declared and not used: b } // 注意:只"赋值"不算使用,必须被"读取"(打印、判断、运算)才算
Python 变量类型可变(x = 5 后 x = "a" 合法);Go 变量类型一旦定下不可变,给 int 变量赋字符串直接编译报错。
Go 声明变量不赋值时会自动填零值,而 Python 变量必须先赋值才能用(否则 NameError)。
五、常量
1 2
# Python:惯例用大写,但本质还是变量,随时能改 PI = 3.14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Go:真正的常量,编译期不可修改 const Pi = 3.14 const Appname = "NOOB"
// 常量组 + iota(常量计数器) const ( a = iota// 0,iota 从 0 开始,每行自动 +1 b // 1 c // 2 d = "ha"// 独立值,iota 仍 +1 e // "ha",沿用上一行表达式 f = 100// 独立值 g // 100 h = iota// 7,恢复使用 iota i // 8 )
Python 的”常量”只是命名约定;Go 的 const 是语法层面的不可变。
iota 是 Go 独有的计数器:在 const 块里每新起一行自动 +1,适合定义枚举、周几、状态码这类递增序列。
六、运算符
三者(Python / Go)基本一致,写法对照:
分类
Python
Go
算术
+ - * / %
同左;整除 Python 用 //,Go 里 int/int 天然整除
幂运算
**
没有 **,用 math.Pow(x, y)
自增/减
x += 1(无 ++)
x++ / x--(是语句,不是表达式)
比较
== != < > <= >=
同左
逻辑
and or not
&& || !(三个符号形式)
赋值复合
+= -= *= /=
同左,另有 <<= >>= &= ^= |=(位运算)
重点:Python 的 and/or/not 变成了 Go 的 &&/||/!,这是写条件时最容易手滑的地方。
七、条件判断
1 2 3 4 5 6 7
# Python if x > 0: print("正数") elif x == 0: print("零") else: print("负数")
1 2 3 4 5 6 7 8
// Go if x > 0 { fmt.Println("正数") } elseif x == 0 { fmt.Println("零") } else { fmt.Println("负数") }
差异:
Python 用缩进区分分支,Go 用 {};else if 和 } 必须在同一行,换行会报错。
Go 的判断条件不需要括号,直接 if x > 0。
Go 支持在 if 里先写初始化语句(Python 没有):
1 2 3
if score := getScore(); score >= 60 { // 先声明 score 再判断 fmt.Println("及格", score) } // score 只在 if 块内有效
八、循环
Go 只有 for 一种循环关键字,用不同写法覆盖 Python 的 for、while、for...else 等场景:
Python
Go
for i in range(10)
for i := 0; i < 10; i++
for x in arr
for i, x := range arr
while cond:
for cond {}
while True:(死循环)
for {}
break / continue
break / continue(一致)
1 2 3
# Python for i inrange(5): print(i)
1 2 3 4 5 6 7 8 9 10 11 12
// Go for i := 0; i < 5; i++ { fmt.Println(i) }
// 遍历切片/数组/字典:range for index, value := range names { fmt.Println(index, value) // 只想要 value 就用 _ 占位 index } for _, value := range names { // 忽略下标 fmt.Println(value) }
提醒:Go 里 for {} 是死循环,和 Python 的 while True: 一样,若没有 break 程序会一直跑(笔者文件里就留着一个 main6 死循环,切记别从 main 调它)。
九、函数
1 2 3
# Python defadd(a, b): return a + b
1 2 3 4
// Go funcadd(a int, b int)int { return a + b }
语法结构:func 函数名(参数列表) 返回值类型 { ... }。参数多个同类型可简写:func add(a, b int) int。
Go 最大的特色是支持多返回值(Python 只能返回一个值,多个要靠元组):
1 2 3 4 5 6 7 8
funcswap(x, y string) (string, string) { // 第一个括号收参数,第二个括号给返回值 return y, x }
funcmain() { a, b := swap("Google", "Runoob") // 按顺序接住两个返回值 fmt.Println(a, b) }
train := names[:trainNum] // 切片切分,对应 Python 的 [0:trainNum] val := names[trainNum : trainNum+valNum] test := names[trainNum+valNum:]
for _, set := range [][]string{train, val, test} { for _, name := range set { copyFile("./wormPic/images/"+name+".jpg", "./out/"+name+".jpg") copyFile("./wormPic/txt/"+name+".txt", "./out/"+name+".txt") } } }