likes
comments
collection
share

云原生探索系列(一):Go基础语法 与 Python 对比(控制结构)

作者站长头像
站长
· 阅读数 27

前言

在写了两篇云原生系列之docker相关的文章后,决定还是先把技术栈Go先学习一遍。因为像Docker、K8s等涉及云原生的基本是使用Go语言来实现的,自己有一些 python语言基础,通过类比学习方式,应该很快可以入门Go。这篇内容将从输出HelloWorld入手,然后介绍条件语句以及循环语句。

Go语言优势

Go 语言是一个可以编译高效,支持高并发的,面向垃圾回收的全新语言。

  • 秒级完成大型程序的单节点编译。
  • 依赖管理清晰。
  • 不支持继承,程序员无需花费精力定义不同类型之间的关系。
  • 支持垃圾回收,支持并发执行,支持多线程通讯。
  • 对多核计算机支持友好。

Go 语言不支持的特性

  • 不支持函数重载和操作符重载
  • 为了避免在C/C++开发中的一些Bug和混乱,不支持隐式转换
  • 支持接口抽象,不支持继承
  • 不支持动态加载代码
  • 不支持动态链接库
  • 通过recover和panic来替代异常机制
  • 不支持断言
  • 不支持静态变量

HelloWorld

Go实现

哈哈,学习编程的第一段代码都是从打印HelloWorld开始,我们也从打印入手,不过加入的解析命令行参数,先看go语言实现代码 main.go

package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	name := flag.String("name", "world", "specify the name you want to say hi")
	flag.Parse()
	fmt.Println("os args is:", os.Args)
	fmt.Println("input parameter is:", *name)
	fullString := fmt.Sprintf("Hello %s from Go\n", *name)
	fmt.Println(fullString)
}

先不管代码逻辑,先编译运行看看输出结果,执行如下命令进行编译:

go build -o ~/GolandProjects/bin/helloworld main.go

-o: 编译后的可执行文件输出到~/GolandProjects/bin目录下,并命名为helloworld。 进入二进制文件目录,执行如下命令:

./helloworld

可以看到输出如下内容:

os args is: [./helloworld]
input parameter is: world
Hello world from Go

执行如下命令:

./helloworld -h

可以看到输出如下内容:

Usage of ./helloworld:
  -name string
    	specify the name you want to say hi (default "world")

从帮助中,我们可以看到,可以指定name 执行如下命令:

./helloworld -name leilei

可以看到输出如下内容:

os args is: [./helloworld -name leilei]
input parameter is: leilei
Hello leilei from Go

解释一下这个简单的Go语言程序,它包含以下几个部分:

  1. 导入包: fmt 和 flag 是Go语言的标准库包,用于打印输出和处理命令行参数。
  2. func main() :这是Go语言程序的入口函数,程序从这里开始执行。
  3. 定义命令行参数:使用flag.String函数定义了一个名为name的命令行参数,指定了默认值为"world" ,并提供了参数说明。
  4. 解析命令行参数:使用flag.Parse()函数解析命令行参数,并将结果保存在相应的变量中。
  5. 打印命令行参数和输入参数:使用fmt.Println函数打印输出了命令行参数os.Args和输入参数*name
  6. 格式化字符串:使用fmt.Sprintf函数生成一个格式化的字符串fullString ,其中包含了输入参数*name
  7. 打印输出:使用fmt.Println函数将格式化的字符串fullString打印输出。

python实现

笔者之前工作中使用python语言居多,就将GO与python做比较,加深记忆。

下面是python实现类似功能, main.py

import sys


if __name__ == '__main__':
    name = "world"
    print(f"sys args is {sys.argv}")
    if len(sys.argv) > 1:
        name = sys.argv[1]
    print(f"input parameter is:{name}}")
    full_string = f"Hello {name} from Python"
    print(full_string)

在Python中,我们使用sys.argv来获取命令行参数, sys.argv[0]表示脚本文件名,后续的参数通过sys.argv[1:]进行访问。在上述代码中,我们检查sys.argv的长度,如果长度大于1,则将第一个参数赋值给name变量。 执行如下命令,

python main.py leilei

输出内容如下:

sys args is ['main.py', 'leilei']
input parameter is: leilei
Hello leilei from Python

当然,我们看到go实现代码中,使用flag处理命令行参数,python也有提供内置的模块argparse可以用于处理命令行参数。优化后的代码如下:

import argparse


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-n", "--name", default="world", help="specify the name you want to say hi")
    args = parser.parse_args()

    print(f"input parameter is:{args.name}")
    full_string = f"Hello {args.name} from Python"
    print(full_string)

首先创建了一个ArgumentParser对象,然后使用add_argument方法定义了一个名为--name(或者简写为-n)的命令行参数,并指定了默认值和帮助信息。接下来,通过调用parse_args方法解析命令行参数,并将结果保存在args变量中。

可以看到,使用argparse模块相较于之前的实现更灵活和易用。

IF

基本用法

与python类似,直接上代码,一看就明白 go实现:

package main

import "fmt"

func main() {
	age := 25
	if age < 18 {
		fmt.Println("You are a minor")
	} else if age >= 18 && age < 60 {
		fmt.Println("You are an adult")
	} else {
		fmt.Println("You are a senior")
	}
}

python实现:

if __name__ == '__main__':
    age = 25
    if age < 18:
        print("You are a minor")
    elif age >= 18 and age < 60:
        print("You are an adult")
    else:
        print("You are a senior")

基本用法很好理解,不多解释了。

条件判断中声明变量

go实现:

func main() {
	if y := 20 - 6; y < 15 {
		fmt.Println("y is less than 15")
	} else {
		fmt.Println("y is greater than or equal to 15")
	}
}

python是不支持这种写法的。

switch

基本使用

小案例:当天是周六或者周日,输出是周末,否则输出是工作日

go实现:

package main

import (
    "fmt"
    "time"
)

func main() {
    day := time.Now().Weekday()
    switch day {
    case time.Saturday, time.Sunday:
        fmt.Println("It's the weekend")
    default:
        fmt.Println("It's a weekday")

}

该示例展示了基本的switch语句,根据条件判断输出不同的结果。 注意:可以同时测试多个可能符合条件的值,使用逗号分割它们,向上面这样case time.Saturday, time.Sunday:

python实现: python3.10后引入类似swicth的语法。之前版本没有。

import datetime

if __name__ == '__main__':
    day = datetime.date.today().weekday()
    match day:
        case 5 | 6:
            print("It's the weekend")
        case _:
            print("It's a weekday")

这里使用 "|" 进行模式组合。

使用表达式

小案例:判断当前小时,小于12输出早上好,小于18输出下午好,否则输出晚上好 go实现:

func main() {
    hour := time.Now().Hour()
	switch {
	case hour < 12:
		fmt.Println("Good morning!")
	case hour < 18:
		fmt.Println("Good afternoon!")
	default:
		fmt.Println("Good evening!")
	}

}

此代码示例展示了在switch中使用表达式的用法,根据表达式的结果判断输出不同的结果。 python实现:

if __name__ == '__main__':
    hour = datetime.datetime.now().hour
    match hour:
        case hour if hour < 12:
            print("Good morning!")
        case hour if hour < 18:
            print("Good afternoon!")
        case _:
            print("Good evening!")

强制执行后面的 case 语句

go语言使用 fallthrough 会强制执行后面的 case 语句。 go实现:

func main() {
    value := 2

	switch value {
	case 1:
		fmt.Println("Value is 1")
		fallthrough
	case 2:
		fmt.Println("Value is 2 or fell through from 1")
		fallthrough
	case 3:
		fmt.Println("Value is 3 or fell through from 2")
	case 4:
		fmt.Println("Value is 3")
		fallthrough
	default:
		fmt.Println("Unknown value")
	}

}

编译执行上面代码,会输出如下内容:

Value is 2 or fell through from 1
Value is 3 or fell through from 2

从以上代码输出的结果可以看出:switch 从第一个判断表达式为 true 的 case 开始执行,如果 case 带有 fallthrough,程序会继续执行下一条 case,且它不会去判断下一个 case 的表达式是否为 true。 python match语法不支持类似fallthrough行为,强制执行后面的case

For循环

Go 只有一种循环结构:for 循环。

基本使用

小案例:使用基本for循环打印1到5的整数 go实现:

func main() {
	for i := 1; i <= 5; i++ {
		fmt.Println(i)
	}
}

python实现:

if __name__ == '__main__':
    for i in range(1, 6):
        print(i)

初始化语句和后置语句是可选的,此场景与 while 等价

小案例: sum 小于 10 的时候计算 sum 自相加后的值. go实现:

func main() {
	sum := 1
	for sum < 10 {
		sum += sum
	}
	fmt.Println(sum)
}

python实现:

if __name__ == '__main__':
    sum_ = 1
    while sum_ < 10:
        sum_ += sum_

    print(sum_)

python中是有while循环的。

无限循环

go实现:

func main() {
	for {
		fmt.Println("loop")
	}
}

python实现:

if __name__ == '__main__':
        while True:
        print("loop")

for-range

遍历数组,切片,字符串,Map 等. go实现:

func main() {
	// 遍历数组
	slice := []int{1, 2, 3, 4, 5}
	for index, value := range slice {
		fmt.Printf("索引:%d,值:%d\n", index, value)
	}
	// 遍历字符串
	fullString := "hello world"
	for index, char := range fullString {
		fmt.Println(index, string(char))
	}
	// 遍历Map
	m := map[string]int{"one": 1, "two": 2, "three": 3}
	for k, v := range m {
		fmt.Println(k, v)
	}

	arr := []*int{new(int), new(int), new(int)}

	// 遍历指针数组
	for _, ptr := range arr {
		fmt.Println(ptr) // 这里输出的是指针的拷贝地址
	}
}

着重说一下遍历指针数组,在每次迭代中,取出的指针地址实际上是原指针地址的一个拷贝。这意味着,你在循环中对取出的指针地址进行操作时,实际上是在操作拷贝后的指针地址,而不是原始的指针地址。 因此,如果你想要修改原始指针数组中的内容,你需要使用索引来直接访问原始数组。

python实现:

for index, value in enumerate([1, 2, 3, 4, 5]):
    print(f"索引:{index},值:{value}")

for index, char in enumerate("hello world"):
    print(index, char)

for k, v in {"one": 1, "two": 2, "three": 3}.items():
    print(f"{k}: {v}")

enumerate函数用于将一个可迭代对象(如列表、元组或字符串)转换为一个枚举对象,该对象可以生成一个由计数(从start开始,默认为0)和可迭代对象中的元素组成的元组序列。

最后

通过类比的方式,快速掌握了条件语句以及循环语句,下一篇将掌握常用数据结构。

转载自:https://juejin.cn/post/7371687296599277619
评论
请登录