人们都在说Go=C+Python,有必要先学个入门再说对不对

x33g5p2x  于2021-11-29 转载在 Go  
字(14.3k)|赞(0)|评价(0)|浏览(151)

本月10日是Go语言发布12周年的纪念日,之前也没有去关注过它;后来听人们都在说 Go = C + Python,还和区块链技术搭界,所以感觉到很有必要去了解了解。

今天是Go语言12周年生日,装一个开始Go语言之旅吧——_汉阳Hann's Home-CSDN博客Go语言的生日12年前的“今天”→ 2009.11.10,Go 语言以开源方式向全球发布!简介Go 语言又称 Golang,是谷歌(Google)开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go语言有时被描述为“C 类似语言”,或者是“21 世纪的C语言”。Go从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等很多思想,还有C语言一直所看中的编译后机器码的运行效率以及和现有操作系统的无缝适配。与 C++ 相比,Go 并不包括如枚举、异

https://hannyang.blog.csdn.net/article/details/121255305上文中已提到过Go的下载和安装了,这次网上搜到一款开源、跨平台的轻量级Go语言集成开发环境(LiteIDE),据说是国人开发的 Google Go 语言的一个开发工具。

Go语言开发工具LiteIDE的安装

下载

下载网址: https://www.cr173.com/soft/44819.html 

网上多数讲的下载地址,已失链: http://golangtc.com/download/liteide

下载成功得到一个压缩包: liteidex37.4.qt4.8.5.zip

安装

压缩包中有两个文件夹: liteide、liteide_win64

根据你安装的Go版本是32位还64位选择对应的文件夹释放到Go安装文件夹下,我的安装在文件夹: d:\go。

运行

然后在D:\Go\liteide\bin里找到 liteide.exe,双击运行。右键点击在任务栏里的“八卦”图标,把它锁定在任务里,或者创建一个桌面快捷方式也可以。

界面

我安装的是X37.4版本:

LiteIDE的使用

文件菜单中“新建”,或者快捷键Ctrl+N新建一个代码,复制以下代码段框中的几行代码,另存为一个源文件helloworld.go。

hello world

万能的hello world,不管学什么语言总要遇到它

package main

import "fmt"

func main() {
    fmt.Println("hello world")
}

解读

  1. package main

每个Go源代码文件的开头都是一个package声明,表示该Go代码所属的包。

包是Go语言里最基本的分发单位,也是工程管理中依赖关系的体现。

要生成Go可执行程序,必须建立一个名字为main的包。

  1. import "fmt"

在包声明之后是import语句,用于导入该程序所依赖的包。

和python一样用import导入,但库名要用引号包括;类似C/C++的include语句。

3. func main()

包main中必须包含一个名为main()的函数(Go可执行程序的执行起点)。

Go语言的main()函数不能带参数,也不能定义返回值。

命令行传入的参数在os.Args变量中保存,如果需要支持命令行开关,可使用flag包。

4. fmt.Println("hello world")

Println()函数,需要导入该函数所属的fmt包。

执行

编译菜单中FileRun,或者使用快捷键 Alt+F6或Alt+Shift+R。

由fmt.Println()输出: hello world。

Go语法基础入门

输出 Print

三种基本形式:带换行、不带换行、使用格式符

fmt.Println("string")
fmt.Print("string")
fmt.Printf("Name: %s, Age: %d\n", "Hann", 48)

与python对比:内置函数不用导入包

print('string')
print('string', end='') 
print('Name: %s, Age: %d'%('Hann',48))

#python 另有两种方法:
print('Name: {}, Age: {}'.format('Hann', 48))
name,age = 'Hann',48
print(f'Name: {name}, Age: {age}')

注释

与C/C++相同,使用 // 或 /*  */

// 单行注释

/* 
  多行注释
*/

Python 则使用井号 # 或者三连引号 """ ... """ 、 ''' ... '''

标识符、关键字

标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。

这些规则,基本上所有语言都是如此。

Go 语言有 25 个关键字(或称为保留字):

| break | default | func | interface | select |
| case | defer | go | map | struct |
| chan | else | goto | package | switch |
| const | fallthrough | if | range | type |
| continue | for | import | return | var |

Go 语言有 36 个预定义标识符

| append | bool | byte | cap | close | complex |
| complex64 | complex128 | copy | false | float32 | float64 |
| imag | int | int8 | int16 | int32 | int64 |
| iota | len | make | new | nil | panic |
| print | println | real | recover | string | true |
| uint | uint8 | uint16 | uint32 | uint64 | uintptr |

Python 只有30来个关键字,上表的标识符也有类似的但没有这么多类型标识符。

程序一般由关键字、常量、变量、运算符、类型和函数组成。

数据类型

布尔型

布尔型的值只可以是常量 true 或者 false,字母全部小写,其格式化符:%t。

Go和Python都是大小写敏感的编程语言,Python使用的布尔值首字母要大写。

数字型

#有符号整数
int8(-128 -> 127)
int16(-32768 -> 32767)
int32(-2,147,483,648 -> 2,147,483,647)
int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)

#无符号整数
uint8(0 -> 255)
uint16(0 -> 65,535)
uint32(0 -> 4,294,967,295)
uint64(0 -> 18,446,744,073,709,551,615)

#浮点型
float32(IEEE-754 32位浮点型数)
float64(IEEE-754 64位浮点型数)
#无float类型

#复数,格式化符:%v
Go 拥有以下复数类型:
complex64 (32 位实数和虚数)
complex128 (64 位实数和虚数)

复数与python基本相同,只是两者的虚数单位不同,Go用的是 i ,python用的是 j 。

Go语言的数字类型比较接近C/C++,不如Python只有int, float, complex来的方便。

变量声明

Go语言引入关键字var,而类型信息放在变量名之后,示例如下:

var v1 int
var v2 string
var v3 [10]int // 数组
var v4 []int // 数组切片

var c1 complex64 = 3 + 23i
fmt.Printf("The value is: %v", c1)  // 输出: 3 + 23i

这一点比Python严格,Python直接赋值即声明,没有声明关键字,且不强制要指定类型。

字符型

字符不是 Go 语言的一个类型,字符只是整数的特殊用例:
1)byte 类型是 uint8的别名:

var ch byte = 'A' 
var ch byte = 65
var ch byte = '\x41'  // \x 总是紧跟着长度为 2 的 16 进制数
/* 以上三行代码等价 */

2) rune 是 int32 的别名。
Unicode 至少占用 2 个字节,所以Go使用 int16 或者 int 类型来表示。如果需要使用到 4 字节,则会加上 \U 前缀;前缀 \u 则总是紧跟着长度为 4 的 16 进制数,前缀 \U紧跟着长度为 8 的 16 进制数。

var ch int = '\u0041'
var ch2 int = '\u03B2'
var ch3 int = '\U00101234'
fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer
fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character
fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes
fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point

对Python来说也没字符类型一说,它可以看作长度为1的字符串。 

字符串类型

字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。

派生类型

这些类型大多是python所没有的,可以找到数组、结构、函数、切片、Map等相近的用法。

零值 nil

Go任何类型在未初始化时都对应一个零值:布尔类型是false,整型是0,字符串是"",而指针,函数,interface,slice,channel和map的零值都是nil。
可以把 nil 看作相当于Python的None。

常量

常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

常量的定义格式: const identifier [type] = value
可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。

显式类型定义: const b string = "abc"
隐式类型定义: const b = "abc"

Python没有常量关键字const的,就是不能被重定义的或值不变的“变量”。

运算符

运算符用于在程序运行时执行数学或逻辑运算。Go 语言内置的运算符有:

算术运算符

+、-、*、/ 加减乘除

、-- 有和C/C一样的自增减运算

没有Python的整除//,和C/C++一样用数据类型来分辨这“两种”运算。

package main
import "fmt"

func main() {
	fmt.Printf("%d", 5/2)
	fmt.Println()
	fmt.Printf("%f", 5/2.0)
}

/*
2
2.500000
*/

关系运算符

==、!=、>、<、>=、<=  这些和Python的都相同。

逻辑运算符

&&、||、!  对应Python的 and、 or、 not 运算。

位运算符

&、|、^ 、<<、>> 和Python相同:“与、或、异或”及左、右位移。

按位取反运算: Go直接用^符号,Python则用~符号。

即: Go语言中,^ 作一元运算符时即按位取反,作二元运算符时即按位异或。

Go语言还特有一个“与非”运算: &^,相当于与运算和非运算的“连写”。

赋值运算符

=、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|= 差不多的,略。

其他运算符

*a    指针变量a
&a    返回变量a的存储地址

这两个运算和C/C++中的用法相同,Python是没有指针的。

控制语句

条件语句

if 语句:

package main

import "fmt"

func main() {

	var a int = 3

	if a < 23 {
		fmt.Printf("a 小于 23\n")
	}

	fmt.Printf("a 的值为 : %d\n", a)
}

if-else语句:

if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
} else {  
  /* 在布尔表达式为 false 时执行 */
}

if- else if-else语句:

package main

import "fmt"

func main() {
    var age int = 23
    if age == 25 {
        fmt.Println("true")
    } else if age < 25 {
        fmt.Println("too small")
    } else {
        fmt.Println("too big")
    }
}

Go的条件语句中else 位置不能新起一行,必须紧跟在右括号后面。

与Python对比,else要另起一行,且Python有关键字elif:

注意:Go没有三目操作符a=b>c?b:c,Python中即 a=b if b>c else c。

开关语句

switch-case-default语句:

package main

import "fmt"

func main() {
	/* 定义局部变量 */
	var grade string = "B"
	var marks int = 90

	switch marks {
	case 90:
		grade = "A"
	case 80:
		grade = "B"
	case 50, 60, 70:
		grade = "C"
	default:
		grade = "D"
	}

	switch {
	case grade == "A":
		fmt.Printf("优秀!\n")
	case grade == "B", grade == "C":
		fmt.Printf("良好\n")
	case grade == "D":
		fmt.Printf("及格\n")
	case grade == "F":
		fmt.Printf("不及格\n")
	default:
		fmt.Printf("差\n")
	}
	fmt.Printf("你的等级是 %s\n", grade)
}

/*
优秀!
你的等级是 A
*/

select-case-default语句:

package main

import "fmt"

func main() {
   var c1, c2, c3 chan int
   var i1, i2 int
   select {
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("sent ", i2, " to c2\n")
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }    
}

Python最新版本3.10.0才开始启用 match - case 开关语句,之前的版本只能使用 if... elif... elif... elif... else... 代替。 

循环语句

Go 只有for循环语句,没有while语句。有多种形态:

实例1:累加1+2+3+...+100

package main

import "fmt"

func main() {
	sum := 0
	for i := 0; i <= 100; i++ {
		sum += i
	}
	fmt.Println(sum)

    // 以下写法就和 While 形式一样,只是关键字没换而已
	sum = 0
	i := 1
	for i <= 100 {
		sum += i
		i++
	}
	fmt.Println(sum)

}

实例2:100以内的素数

package main

import "fmt"

func main() {
	// var prime,c int   //定义变量不使用也会报错
	var prime int
	var flag bool
	prime = 1
	//while(prime<100) {    //Go语言没有while
	for prime < 100 {
		prime++
		flag = true
		//注意循环变量使用:=赋值
		for tmp := 2; tmp < prime; tmp++ {
			if prime%tmp == 0 {
				flag = false
			}
		}

		if flag == true {
			fmt.Println(prime, "是素数")
		} else {
			continue
		}
	}
}

/*
2 是素数
3 是素数
5 是素数
7 是素数
11 是素数
13 是素数
17 是素数
19 是素数
23 是素数
29 是素数
31 是素数
37 是素数
41 是素数
43 是素数
47 是素数
53 是素数
59 是素数
61 是素数
67 是素数
71 是素数
73 是素数
79 是素数
83 是素数
89 是素数
97 是素数
*/

“容器”类型

数组(列表)、切片(Slice)

package main

import "fmt"

func main() {
	// initialized array
	var numbers [5]int // becomes [0, 0, 0, 0, 0]
	// change one of them
	numbers[2] = 100
	// create a new slice from an array
	some_numbers := numbers[1:3]
	fmt.Println(some_numbers) // [0, 100]
	// length of it
	fmt.Println(len(numbers))

	// initialize a slice
	var scores []float64
	scores = append(scores, 1.1) // recreate to append
	scores[0] = 2.2              // change your mind
	fmt.Println(scores)          // prints [2.2]

	// when you don't know for sure how much you're going
	// to put in it, one way is to
	var things [100]string
	things[0] = "Peter"
	things[1] = "Anders"
	fmt.Println(len(things)) // 100
}

对比Python: 

范围(Range)

package main
import "fmt"

func main() {
	names := []string{
		"Hann",
		"Yang",
		"Hann Yang",
	}

	for i, name := range names {
		fmt.Printf("%d. %s\n", i+1, name)
	}
}

对比Python: 

Map(集合)

package main

import "fmt"

func main() {
	elements := make(map[string]int)
	elements["H"] = 1
	fmt.Println(elements["H"])

	// remove by key
	elements["O"] = 8
	delete(elements, "O")

	// only do something with a element if it's in the map
	if number, ok := elements["O"]; ok {
		fmt.Println(number) // won't be printed
	}
	if number, ok := elements["H"]; ok {
		fmt.Println(number) // 1
	}

}

对比Python: 

函数 func

函数定义

Go 语言函数定义格式如下:

定义解析:

Go的函数用func起头,函数体和C/C++一样用{}包括代码,但代码语句不用“ ;”表示结束。

与Python的比较:deffuncname()**: **起头的关键字不一样,python不用{}括号但要用“ : ”;以及有强制而严格的缩进。

函数调用

当创建函数时,定义的函数需要做什么,通过调用该函数来执行指定任务。

调用函数,可以向函数传递参数,并返回值:

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int = 200
   var ret int

   /* 调用函数并返回最大值 */
   ret = max(a, b)

   fmt.Printf( "最大值是 : %d\n", ret )
}

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 定义局部变量 */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result
}

对比Python: 

多个返回值

package main

import "fmt"

func swap(x, y int) (int, int) {
	return y, x
}

func main() {
	a, b := swap(3, 23)
	fmt.Println(a, b)
}

对比Python: 即返回值是一个元组tuple()

递归函数

实例1:阶乘

package main

import "fmt"

func Factorial(n uint64)(result uint64) {
    if (n > 0) {
        result = n * Factorial(n-1)
        return result
    }
    return 1
}

func main() {  
    var i int = 15
    fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}

实例2:斐波那契数列

package main

import "fmt"

func fibonacci(n int) int {
	if n == 1 || n == 2 {
		return 1
	}
	return fibonacci(n-2) + fibonacci(n-1)
}

func main() {
	var i int
	for i = 1; i <= 10; i++ {
		fmt.Printf("%d\t", fibonacci(i))
	}
}

Python这两个函数练得太多了,略。

函数嵌套

package main

import "fmt"

func main() {

	number := 0

	/* It has to be a local variable like this.
	   You can't do `func increment(amount int) {` */
	increment := func(amount int) {
		number += amount
	}
	increment(1)
	increment(2)
    increment(5)

	fmt.Println(number) // 8

}

对比Python: 

内置函数

内置函数是不需要引入包直接可用的函数。

常用包

time包

常量

const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)

实例 

package main

import (
	"fmt"
	"time"
)

func main() {
	t0 := time.Now()
	time.Sleep(3*time.Second + 230*time.Millisecond)
	elapsed := time.Since(t0)
	fmt.Printf("Took %s", elapsed)
}

对比Python: 

math包

常量

E = 2.71828182845904523536028747135266249775724709369995957496696763
Pi = 3.14159265358979323846264338327950288419716939937510582097494459
Phi = 1.61803398874989484820458683436563811772030917980576286213544862
Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974
SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931
SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779
SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038
Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009
Log2E = 1 / Ln2
Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790
Log10E = 1 / Ln10

MaxFloat32 = 3.40282346638528859811704183484516925440e+38 
// 2**127 * (2**24 - 1) / 2**23
SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 
// 1 / 2**(127 - 1 23)
MaxFloat64 = 1.797693134862315708145274237317043567981e+308 
// 2**1023 * (2**53 - 1) / 2**52
SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 
// 1 / 2**(1023 - 1 52)

极值 

MaxInt8 = 1<<7 - 1
MinInt8 = -1 << 7
MaxInt16 = 1<<15 - 1
MinInt16 = -1 << 15
MaxInt32 = 1<<31 - 1
MinInt32 = -1 << 31
MaxInt64 = 1<<63 - 1
MinInt64 = -1 << 63
MaxUint8 = 1<<8 - 1
MaxUint16 = 1<<16 - 1
MaxUint32 = 1<<32 - 1
MaxUint64 = 1<<64 - 1

常用数学函数

/*IsNaN函数
func IsNaN(f float64) (is bool)
报告f是否表示一个NaN(Not A Number)值,是数值返回一个false,不是数值则返回一个true。
*/
func testIsNaN() {
	fmt.Println(math.IsNaN(12321.321321))    //false
}

/*Ceil函数
func Ceil(x float64) float64
返回一个不小于x的最小整数,简单来说就是向上取整
*/
func testCeil() {
	fmt.Println(math.Ceil(1.13456))    //2
}

/*Floor函数
func Floor(x float64) float64
返回一个不大于x的最小整数,简单来说就是向下取整
*/
func testFloor() {
	fmt.Println(math.Floor(2.9999))    //2
}

/*Trunc函数
func Trunc(x float64) float64
返回x整数部分,与Floor一样
*/
func testTrunc() {
	fmt.Println(math.Trunc(2.9999))    //2
}

/*Abs函数
func Abs(x float64) float64
返回x的绝对值
*/
func testAbs() {
	fmt.Println(math.Abs(2.999312323132141665374))    //2.9993123231321417
	fmt.Println(math.Abs(2.999312323132141465374))    //2.9993123231321412
}

/*Max函数
func Max(x, y float64) float64
返回x和y中最大值
*/
func testMax() {
	fmt.Println(math.Max(1000,200))    //1000
}

/*Min函数
func Min(x, y float64) float64
返回x和y中最小值
*/
func testMin() {
	fmt.Println(math.Min(1000,200))    //200
}

/*Dim函数
func Dim(x, y float64) float64
函数返回x-y和0中的最大值
*/
func testDim() {
	fmt.Println(math.Dim(1000,2000))    //0
	fmt.Println(math.Dim(1000,200))    //800
}

/*Mod函数
func Mod(x, y float64) float64
取余运算,可以理解为 x-Trunc(x/y)*y,结果的正负号和x相同
*/
func testMod() {
	fmt.Println(math.Mod(123,0))    //NaN
	fmt.Println(math.Mod(123,10))    //3
}

/*Sqrt函数
func Sqrt(x float64) float64
返回x的二次方根,平方根
*/
func testSqrt() {
	fmt.Println(math.Sqrt(144))    //12
}

/*Cbrt函数
func Cbrt(x float64) float64
返回x的二次方根,平方根
*/
func testCbrt() {
	fmt.Println(math.Cbrt(1728))    //12
}

/*Hypot函数
func Hypot(p, q float64) float64
返回Sqrt(p*p q*q),注意要避免不必要的溢出或下溢。
*/
func testHypot() {
	fmt.Println(math.Hypot(12,12))    //16.970562748477143
}

/*Pow函数
func Pow(x, y float64) float64
求幂,x的y次方
*/
func testPow() {
	fmt.Println(math.Pow(2,3))    //8
}

/*Sin函数
func Sin(x float64) float64
求正弦
*/
func testSin() {
	fmt.Println(math.Sin(12))    //-0.5365729180004349
}

/*Cos函数
func Cos(x float64) float64
求余弦
*/
func testCos() {
	fmt.Println(math.Cos(12))    //0.8438539587324921
}

/*Tan函数
func Tan(x float64) float64
求正切
*/
func testTan() {
	fmt.Println(math.Tan(12))    //-0.6358599286615807
}

/*Log函数
func Log(x float64) float64
求自然对数
*/
func testLog() {
	fmt.Println(math.Log(2))    //0.6931471805599453
}

/*Log2函数
func Log2(x float64) float64
求2为底的对数
*/
func testLog2() {
	fmt.Println(math.Log2(128))    //7
}

/*Log10函数
func Log10(x float64) float64
求10为底的对数
*/
func testLog10() {
	fmt.Println(math.Log10(10000))    //4
}

/*Signbit函数
func Signbit(x float64) bool
如果x是一个负数或者负零,返回真
*/
func testSignbit() {
	fmt.Println(math.Signbit(10000))    //false
	fmt.Println(math.Signbit(-200))    //true
}

实例

package main

import (
	"fmt"
	"math"
)

func main() {
	var x float64
	var n int
	fmt.Scanf("%f%d", &x, &n)
	fmt.Println(powerf(x, n))
	fmt.Println(powerf2(x, n))
	fmt.Println(powerf3(x, n))
	fmt.Println(math.Pow(x, float64(n)))
}

//二分法
func powerf(x float64, n int) float64 {
	ans := 1.0
	for n != 0 {
		if n%2 == 1 {
			ans *= x
		}
		x *= x
		n /= 2
	}
	return ans
}

//递归法
func powerf2(x float64, n int) float64 {
	if n == 0 {
		return 1
	} else {
		return x * powerf2(x, n-1)
	}
}

//循环法
func powerf3(x float64, n int) float64 {
	ans := 1.0
	for n != 0 {
		ans *= x
		n--
	}
	return ans
}

本篇学到这里暂告一段落,以上内容都能领会的话,常见的小问题简单的入门基础题基本上都能解决了; Go语言还有很多高级内容,拟列入Golang进阶之路中......

参考内容

  1. Runoob: https://www.runoob.com/go/go-tutorial.html

2. Go vs. Python: http://govspy.peterbe.com/

3. 《Go语言编程》许式伟 吕桂华 等编著,人民邮电出版社出版发行

相关文章