哈哈哈,其实这个系列如题,就是黄同学也参加了这一届青训营。作为一名知识内容输出爱好者,我是非常喜欢这个活动的。在接下来的日子里我会持续更新这个系列,希望可以通过这个过程,将我在这次后端青训营的学习过程,尤其是针对课程中知识内容的课下实践,自己的心得体会,知识总结输出到掘金社区。
哈哈哈,其实也希望通过这个来对我这种懒狗的一种鞭策。
事先说明,黄同学在这次青训营之前并没有任何Go语言相关的经历,唯一算有的,可能就是闲的时候看过几篇Go相关的文章,如果有写得不对的地方,希望大家能够指出 。
Go
的另外一个名字是 Golang
,是由 Google
支持的一种编程语言。在我过去的认知中,Go主要用于服务端的开发。goroutine
和 channel
。这个以后有机会深入研究然后发出来和大家一同讨论,哈哈哈,希望不会。C
和 C++
的我来说,Go语法,尤其是变量初始化类型在后面这一点确实令我不是很能适应,不过也有通过 :=
这种来初始化的方式让我比较好接受。JAVA
类似,具有垃圾回收机制与跨平台特点,相比像C
等需要开发者管理内存,要更方便。C++
,Java
,Python
等的环境配置,很多时候都比较复杂。但是,幸运的是,Go
的环境配置很简单:happy:。next
,中间如果你想选择环境的路径,可以选择,默认应该是C
下的一个program
的子目录。Path
点击编辑,点击新建,输入在前面安装Go环境的路径配置。设置环境变量, 主要是希望通过配置环境变量后,OS会在执行Go程序的时候,会载入Go的配置进行解析。可以参考下列配置。go version
,如果返回版本信息,说明你已经成功安装并配置了Go环境。vscode
,严格来说,这个并不是IDE,而是一个轻量级的编辑器,但是可以通过安装一系列的拓展插件,比如Go插件实现的IDE级别的功能。好处在于轻量级,完全免费。Goland
,Jetbrians针对Go开发的IDE,最新版的UI我很喜欢,当然用过idea 或者pychcarm 会发现界面非常像,因为是一个公司做的。黄同学使用的时候,感觉要比vscode 丝滑:happy:。缺点在于收费,而且小贵,基本上每年要100到200多刀乐,相比pycharm,idea没有社区版,也就是说必须付费,但是有30天的体验期,且如果你和黄同学一样是个大学生(虽然很快就不是了),你可以申请免费使用了。IDEA Ultimate
,必须是专业版哦,因为只有专业版才支持Go插件,使用上基本和Goland一致,但需要去配置Go插件,并且设置Go环境地址。好处在于你可以用这个IDE去玩很多语言,不只是Go和Java,还可以是Python等。注意:如果你是简洁到极致的,你可以不用这些,至于运行,可以直接用 go run
或者 go build
命令。
这个是黄同学在参加青训营的时候发现使用的,很好理解,就是青训营官方将代码上传到了Gitpod
,其他人可以通过Gitpod 去编辑代码。
Jetbrians gateway
来搭配使用。万恶的开始,哈哈哈,开玩笑的。其实我们很多人的编程开始都是来自于那一句 Hello world
。
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
通过这个作为开头,相信朋友们已经发现了,Go和Python类似,不需要打 ;
来作为结尾。
变量有两种声明与初始化方式:
使用 var
,变量名后面可用类型关键字(这一点好难受 ),当然也可以省略,如果要初始化用=
来初始化,会自动根据值确定类型,又Python一样。
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
使用 :=
来声明并初始化变量,这个感觉更舒服一点。
f := float32(e)
g := a + "foo"
注意:go中并没有char
,而是rune
,是int32
的别名,表示一个Unicode
码点。
常量,你只需要在最开头用 const
关键字,表示这是一个常量。类型关键字可写可不写。
const s string = "constant"
const h = 50000000
const i = 3e20 / h
1. Go中有两种,一种是`if-else`,一种是 `switch-case`。
2. Go 不支持三目运算符,理由似乎是认为这个是不清晰的。
有几个细节:
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
t := time.Now()
fmt.Println("the time now is " + strconv.Itoa(t.Hour()) + "h") /* print the time's hour now */
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
i := 1
for {
fmt.Println("loop")
break
}
for j := 7; j < 9; j++ {
fmt.Println(j)
}
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i++
}
:
来快速选择子数组。[]
里边指定长度,如果不指定,那么就是切片。 var a [5]int /* 所有元素初始化为0 */
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4} /* 按序,未初始化部分则默认为0 */
fmt.Println(b)
fmt.Println("array's slice:", b[2:])
var twoD [2][3]int
twoD1 := [2][3]int{}
fmt.Println("twoD1:", twoD1) /**/
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
C++
的 vector
,是长度可变的数组。make
,一种是和数组类似,但是不指定长度。append
的时候,需要赋值操作才能改变原数组的长度,其实是要接收长度变化后的结果。 s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
key-value
的数据结构。 m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m)
fmt.Println(len(m))
fmt.Println(m["one"])
fmt.Println(m["unknow"])
r, ok := m["unknow"]
fmt.Println(r, ok)
r, ok = m["two"]
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)
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num)
}
}
fmt.Println(sum)
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v)
}
for k := range m {
fmt.Println("key", k)
}
func add(a int, b int) int {
return a + b
}
func add2(a, b int) int {
return a + b
}
C++
使用者。func add2(n int) {
n += 2
a := &n
fmt.Println("add2:", *a)
}
值传递
func add2(n int) {
n += 2
a := &n
fmt.Println("add2:", *a)
}
指针传递
func add2ptr(n *int) {
*n += 2
}
⚠️ 注意:数组是值传递,切片是指针传递(传递指针,切片本身是包括了指向底层数组的指针,长度)
type
开头type user struct {
name string
password string
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
java
等那种try-catch
结构要好一些,个人看法。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")
}
string
库。Contains
,Count
,Join
,Replace
等。func main() {
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // true
fmt.Println(strings.Count(a, "l")) // 2
fmt.Println(strings.HasPrefix(a, "he")) // true
fmt.Println(strings.HasSuffix(a, "llo")) // true
fmt.Println(strings.Index(a, "ll")) // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2)) // hellohello
fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo, -1表示替换的数量没有限制
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
fmt.Println(a)
fmt.Println(strings.ToLower(a)) // hello
fmt.Println(strings.ToUpper(a)) // HELLO
fmt.Println(len(a)) // 5
b := "你好"
fmt.Println(len(b)) // 6 一个中文字相当于3个英文字符
}
Hello World
的例子中,就用到了fmt,这个其实就是一个标准输出库(字符串格式化)。%v
,任意类型的变量。%+v
,详细结果。%#v
,更详细。 s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
fmt.Printf("s=%v\n", s) // s=hello
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(buf)
fmt.Println(string(buf))
var b userInfo
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%v\n", b)
Date
接口设置时间,创建时间变量。Format
指定格式。 now := time.Now()
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
diff := t2.Sub(t)
fmt.Println(diff) // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) // true
fmt.Println(now.Unix()) // 1648738080
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
// go run example/20-env/main.go a b c d
fmt.Println("Args:", os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
fmt.Println("Path:", os.Getenv("PATH")) // /usr/local/go/bin...
fmt.Println("Set:", os.Setenv("AA", "BB"))
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1 localhost
黄同学在这次编写以及实践中,总结了一些个人的一些经验。
黄同学在编写这篇文章,除了自己的实践外,还参考了不少资料。如果朋友想要通过我的这篇简陋笔记文章去探索那些可以称为宝玉或者 般的知识,不妨通过下面的链接看看: