前言
有一定的C++基础,写过一些数据结构和算法,力扣刷过一些题。Python研究生阶段有自学,帮别人改模型和跑模型。没有接触过Go语言。
1.1 Go特性
高性能、高并发;语法简单、学习曲线平缓(一周?);丰富的标准库(类似Python?);完善的工具链;静态链接(编译到一个可执行文件?);快速编译;跨平台(还可以开发安卓、IOS);垃圾回收(new、delete?)
字节最开始居然使用Python写的...
2 Go配置环境
2.1 安装Golang
2.2 IDE(Vscode)
平常用的是Vscode,所以尝试着在vscode上配置go,参考的是这篇博客:GO开发环境配置_go环境配置_astrolabium的博客-CSDN博客
中间遇到了两个问题: 1.安装go tools碰到了失败,参考: 解决VSCode安装Go tools失败的问题 - 知乎 (zhihu.com) 2.配置完后,运行hello,world程序时,出现错误:hello.go:1:1: expected 'package', found 'EOF' 解决:运行前要保存文件,GO文件在运行前一定要按Ctrl+s保存吗?
尝试了所有程序员的第一个程序(梦回17年):
package main
import "fmt"
func main() {
fmt.Println("Hello World go!")
}
package main:表示主程序?
fmt:类似于Python那些包,GO也是需要导入很多包的,但是与Python不同的是: Python导入不需要的包的时候不会报错,GO会报错。
func main() : 类似C++ int main(), 主程序代码所在
3 本节课代码
在历时两个小时的看课加一遍写代码,把这节课听完了,着实有点耗时间。
看的这节课类似于看了“菜鸟教程”似的,基本就是把所有的用法直接罗列一遍,不过也确实学到了很多Go的用法,也真切的体会到了,Go很多与C++和Python的相同和不同之处吧。
package main
import "fmt"
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n)
fmt.Println(p)
fmt.Printf("s=%v\n", s) // printf 类似于C语言的输出, %v 指的就是后面的数值
fmt.Printf("n=%v\n", n) // 无论什么类型,都会把其中存的数值输出出来
fmt.Printf("p=%v\n", p)
fmt.Printf("p=%+v\n", p) // %+v , 就会输出字段的名字和值
fmt.Printf("p=%#v\n", p) // %#v, 打印的更详细
f := 3.1415926
fmt.Println(f)
fmt.Printf("%.2f\n", f) // 可以使用%.2f输出只保留两位小数
}
package main
import "fmt"
func main() {
i := 1
for { // 死循环
fmt.Println("loop")
i++
if i == 10 {
break
}
}
for j := 1; j < 9; j++ {
if j%2 == 0 {
continue
}
if j == 8 {
break
}
fmt.Println(j)
}
// while i < 19 { // 没有 while循环
// }
}
package main
import "fmt"
func main() { // map是完全无序的,遍历是不会按照插入顺序输出,是偏随机的
m := make(map[string]int) // 定义方式
m["one"] = 1
m["two"] = 2
fmt.Println(m)
fmt.Println(len(m))
fmt.Println(m["one"])
r, ok := m["unknow"] // ok 用来判断相应的key是否存在
fmt.Println(r, ok)
delete(m, "one")
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
}
package main
import (
"fmt"
"strconv" // 字符串和数字之间的转换
)
func main() {
f, _ := strconv.ParseFloat("1.234", 64) // 解析一个字符串
fmt.Println(f)
n, _ := strconv.ParseInt("111", 10, 64) // 解析一个字符串, 10 表示进制, 64位精度
fmt.Println(n)
n, _ = strconv.ParseInt("0x1000", 0, 64) // 0 表示自动推测
fmt.Println(n)
n2, _ := strconv.Atoi("123") // 快速把一个十进制字符串转换成一个数字
fmt.Println(n2)
n2, err := strconv.Atoi("AAA") // 不合法会返回一个err
fmt.Println(n2, err)
}
package main
import "fmt"
func add2(n int) { // 与C++相同, 传入时是copy了一个新的变量,对之前的变量无法做到更改
n += 2
}
func add2ptr(n *int) { // 指针定义, *int 后置
*n += 2
}
func main() {
n := 5
add2(n)
fmt.Println(n)
add2ptr(&n) // 与C++一致, 传入地址
fmt.Println(n)
}
package main
import "fmt"
func main() {
s := make([]string, 3) // 初始默认了长度3
s[0] = "0"
s[1] = "1"
s[2] = "2"
fmt.Println("get :", s[2])
fmt.Println("len :", len(s))
s = append(s, "d") // 类似Python 有append用法
s = append(s, "e", "f")
fmt.Println(s)
c := make([]string, len(s))
copy(c, s)
fmt.Println(c)
fmt.Println(s[2:5]) // 类似Python
fmt.Println(s[:5])
// fmt.Println(s[2:-1]) // 有问题, 和Python不同了 -1 不指最后一位
fmt.Println(s[2:])
good := []string{"g", "o", "o", "d"} // 没初始长度
fmt.Println(good)
}
package main
import "fmt"
type user struct {
name string
password string
}
func (u user) checkPassword(password string) bool { // 结构体成员函数,定义方法
return u.password == password
}
func (u *user) checkPassword2(password string) bool { //
return u.password == password
}
func main() {
a := user{name: "wang", password: "1024"} // 结构体的几种定义方法
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d)
fmt.Println(a.checkPassword("1023")) // 用的时候就可以使用 "." 来使用了
fmt.Println(b.checkPassword2("1024"))
fmt.Println(c.checkPassword("1111"))
fmt.Println(d.checkPassword2("1024"))
}
package main
import "fmt"
type user struct { // 后置有点太不习惯了
name string
password string
}
func main() {
a := user{name: "wang", password: "1024"} // 结构体的几种定义方法
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d)
fmt.Println(checkPassword(a, "haha"))
fmt.Println(checkPassword2(&a, "1024"))
}
func checkPassword(u user, password string) bool {
return u.password == password
}
func checkPassword2(u *user, password string) bool { // 结构体做参数的时候也可以是指针
return u.password == password
}
package main
import (
"fmt"
"time"
)
func main() {
a := 2
switch a {
case 1: // 不用写break,默认不继续执行
fmt.Println("one")
case 2:
fmt.Println("tow")
case 3:
fmt.Println("three")
case 4, 5: // 可以这样用...
fmt.Println("four or five")
default:
fmt.Println("default")
}
t := time.Now() // 访问系统时间
switch { // 还可以不用写变量
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
}
package main
import (
"fmt"
"math"
)
func main() {
var a = "initial" // 自动匹配变量类型
var b, c int = 1, 2 // 自己设定变量类型
var d = true
var e float64 // 未初始化
f := float32(e) // 赋值e
g := a + "foo"
fmt.Println(a, b, c, d, e, f, g) // g 如果没有被使用也会出现报错,跟Python不同
const s string = "constant" // 没有确定类型,根据上下文确定
const h = 50000000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h), math.Sin(i)) // math包可以提供一些基本函数
}
package main
import (
"errors"
"fmt"
)
type user struct {
name string
password string
}
func findUser(users []user, name string) (v *user, err error) { // 使用返回值来显示错误
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil { // 有error
fmt.Println(err)
return
}
fmt.Println(u.name) // 或者返回值
if u, err := findUser([]user{{"wang", "1024"}}, "zhang"); err != nil {
fmt.Println(err)
return
} else {
fmt.Println(u.name)
}
}
4.总结
- 个人感觉Go相较于C++ 和 Python还是有着很多的不同之处的,感觉学过C++ 和 Python的对于第一节课而言还是比较容易入门的。
- 在学习Go的时候,类型后置确实很不习惯,不太清楚为什么选择这个方式,学习C++ 前置类型不是挺好的吗?
- Go里的一个错误处理方式还不错,函数可以直接返回一些错误信息,可以直接print错误信息。
- 类似于Python, Go有很多功能强大的包,可以方便的调用很多函数,可以沟通进程等,我也只是在Python中连接过数据库做过实验,之前也没在C++和Python中试过和进程相关的代码,还是比较新奇的。