实践_Go基础语法_1 | 青训营

73 阅读7分钟

1 特性

  • 标准库就考虑性能, 但却是编译型语言
  • 跨平台
  • C, 强类型
  • 带垃圾回收
  • Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言。( 果然, 新语言就是没有语言包袱, 想怎么设计就怎么设计, )

2 用的公司

  • 腾讯
  • 美团
  • 滴滴

3 why go

  • 最初使用的Python由于性能问题换成了Go
  • C++不太适合在线Web业务早期
  • 内部RPC和HTTP框架的推广
  • 如果你要创建系统程序,或者基于网络的程序,Go语言是很不错的选择。
  • 携程等并发模型

OOP 与 Go

Go 语言在设计上不是一种典型的面向对象编程语言,而是一种以并发和简洁为主要目标的编程语言。尽管如此,Go 语言仍然支持面向对象编程的一些概念和特性。

Go 语言通过结构体(struct)和方法(method)来实现对面向对象编程的支持。结构体可以用于封装数据和行为,并且可以定义方法来操作结构体实例。这样就能够实现面向对象编程中的封装、继承和多态等概念。

尽管 Go 语言没有经典面向对象语言中的类(class)的概念,但可以使用结构体和方法组合来模拟类的行为。通过在结构体上定义方法,可以实现对结构体的操作和行为的封装。

除了结构体和方法,Go 语言还提供了接口(interface)的概念,它定义了一组行为规范。通过实现接口,可以实现多态的效果,使不同类型的对象可以根据接口进行统一的处理。

需要注意的是,Go 语言更强调简洁和可读性,相比于传统的面向对象编程语言,Go 语言更加注重可组合性和函数式编程的思想。因此,在使用 Go 语言进行开发时,可以灵活地选择使用面向对象编程的特性来组织代码结构,或者使用其他更适合的编程范式。

// c 风格 api
s = append(s, "d")
s = append(s, "e", "f")

// 对象式

学习平台

gitpod.io/#github.com…

短链接:hi-hi.cn/gitpod

gitpod 这个效果还挺好看

编译与运行

单文件

# 运行
go run helloworld.go

# 编译
go build helloworld.go

语法

  • 没有括号
  • 变量类型后置
  • 支持返回多个值
package main

import "fmt"

func main() {
    fmt.Println("Hello, 世界")
}

如何组织代码

  • Go语言的代码通过(package)组织,包类似于其它语言里的(libraries)类推==>STL或者模块(modules)python。一个包由位于单个目录下的一个或多个.go源代码文件组成,目录定义包的作用。每个源文件都以一条package声明语句开始,这个例子里就是package main,表示该文件属于哪个包,紧跟着一系列导入(import)(python)的包,之后是存储在这个文件里的程序语句。
  • 类似于pythonGo语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。实际上,编译器会主动把特定符号后的换行符转换为分号,因此换行符添加的位置会影响Go代码的正确解析(译注:比如行末是标识符、整数、浮点数、虚数、字符或字符串文字、关键字breakcontinuefallthroughreturn中的一个、运算符和分隔符++--)]}中的一个)
  • Go语言在代码格式上采取了很强硬的态度。gofmt工具把代码格式化为标准格式, ctrl + s以后自动格式化, 妙蛙
  • 包导入顺序并不重要;gofmt工具格式化时按照字母顺序对包名排序。(我看不懂, 大为震撼)
// 多个包
import{
    "fmt"
    "os"
}

func

类型与变量

  • 类型不需要导入
  • 可以使用 const修饰
  • 短变量声明是一种简洁的变量声明方式,用于同时声明和初始化变量。
var b, c int = 1, 2
var e float64

// 短变量声明
f := a


// 数组
var a [5]int
b := [5]int{1, 2, 3, 4, 5}

// 多维数组
var twoD [2][3]int


// 无力吐槽了 int* arr = new int[size];
s := make([]string, 3)

// c 风格 api
s = append(s, "d")
s = append(s, "e", "f")

// ------------map-------------
m := make(map[string]int)

new 和 make

  • 也是像 C++

在 Go 语言中,makenew 是两个用于创建对象的关键字,但它们用途不同。

  • newnew 用于创建各种类型的指针,并分配了零值。例如,使用 new 可以创建一个指向整数、结构体或数组的指针,而指针指向的内容会被初始化为对应类型的零值。对于数组来说,返回的是指向数组的指针。

    var p *int = new(int) // 创建一个指向 int 类型的指针,并初始化为零值
    fmt.Println(*p) // 输出:0
    
    var arr *[]int = new([]int) // 创建一个指向 int 类型切片的指针,并初始化为零值
    fmt.Println(*arr) // 输出:[]
    
  • makemake 用于创建切片、映射和通道等引用类型的对象,并进行初始化。它会分配内存并返回一个已经初始化的非零值对象。对于切片、映射和通道来说,返回的是对象本身(非指针)。

    slice := make([]int, 5, 10) // 创建一个长度为 5,容量为 10 的 int 类型切片
    fmt.Println(slice) // 输出:[0 0 0 0 0]
    
    m := make(map[string]int) // 创建一个 key 为字符串,value 为整数的映射
    m["foo"] = 42
    fmt.Println(m) // 输出:map[foo:42]
    
    ch := make(chan int) // 创建一个整数类型的通道
    

控制流

for j := 7; j < 9; j++ {
	fmt.Println(j)
}

// 大为震撼.jpg
for {
    // ...
}


// else 空行不限制
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")
}

函数和方法

函数

  • 类型在变量名后
  • 如果你有多个参数的类型相同,你可以进行简写,只需要在这几个相同的参数最后写一遍类型即可。
  • 函数可以有 0 个或多个返回值。和参数不同,有几个返回值就写几个返回值类型,不能简写。
package main
​
import "fmt"func add(x int, y int) int {
    return x + y
}
​
func main() {
    fmt.Println(add(1, 2))
}
​

通过给返回值进行命名,使用空 return 语句,这样会直接返回已命名的返回值。

func sumAndDiff(x, y int) (sum int, diff int) {//提前命名返回值
    sum = x + y
    diff = x - y //返回值在函数中被初始化
    return //返回值已经初始化了,不需要再在return语句中写变量了
}

导出

  • 在 Go 语言中,如果一个名字以大写字母开头,那么它就是已导出的,这意味着别的包可以使用它。(相当于 Java 中的 public 的作用)
  • 比如我们常用的打印函数 fmt.Println(...),可以看到 Println() 的首字母是大写的,所以我们能够导入 fmt 包后使用该方法。

方法

  • Go 中也有类似于面向对象中方法的概念,也叫方法(method),这种方法其实是一种特殊的函数function)—— 带有接收者(receiver)的函数。
  • 通过. 可以调用方法
  • 通过交换函数名以及 函数参数来区分函数以及方法
  • 有点类似于传入指针
package main
​
import "fmt"type dog struct {
    name string
}
​
func (d dog) say() {//方法
    fmt.Println(d.name + " 汪汪汪。。。方法")
}
​
func main() {
    d := dog{"哮天犬"}
    d.watchDoor()
}
​
​

可以实现一种多态性

  • 相同的方法名, 但是不同的对象(结构体)调用
package main
​
import "fmt"type dog struct {
    name string
}
​
type cat struct {
    name string
}
​
type rabbit struct {
    name string
}
​
// 使用 函数来实现, 需要不同的函数名
func dogSay(d dog) {
    fmt.Println(d.name + " 汪汪汪。。。函数")
}
​
func catSay(c cat)  {
    fmt.Println(c.name + " 喵喵喵。。。函数")
}
​
func (d dog) say() {
    fmt.Println(d.name + " 汪汪汪。。。方法")
}
​
// 使用方法来实现, 相同的函数名就可以
func (c cat) say()  {
    fmt.Println(c.name + " 喵喵喵。。。方法")
}
​
func (r rabbit) say() {
    fmt.Println(r.name + " 吱吱吱。。。方法")
}
​
func main() {
    d := dog{"哮天犬"}
    c := cat{"加菲猫"}
    r := rabbit{"玉兔"}
​
    d.say() //调用
    c.say()
    r.say()
}
​

常用的包

fmt

fmt.Println("hello world")