Skip to main content

Go 编程语言的简单介绍 | Linux 中国


(以下内容是我的硕士论文的摘录,几乎是整个 2.1 章节,向具有 CS 背景的人快速介绍 Go)
Go 是一门用于并发编程的命令式编程语言,它主要由创造者 Google 进行开发,最初主要由 Robert Griesemer、Rob Pike 和 Ken Thompson 开发。这门语言的设计起始于 2007 年,并在 2009 年推出最初版本;而第一个稳定版本是 2012 年发布的 1.0 版本。1
Go 有 C 风格的语法(没有预处理器)、垃圾回收机制,而且类似它在贝尔实验室里被开发出来的前辈们:Newsqueak(Rob Pike)、Alef(Phil Winterbottom)和 Inferno(Pike、Ritchie 等人),使用所谓的 Go 协程goroutines信道channels(一种基于 Hoare 的“通信顺序进程”理论的协程)提供内建的并发支持。2
Go 程序以包的形式组织。包本质是一个包含 Go 文件的文件夹。包内的所有文件共享相同的命名空间,而包内的符号有两种可见性:以大写字母开头的符号对于其他包是可见,而其他符号则是该包私有的:
  1. func PublicFunction() {
  2.    fmt.Println("Hello world")
  3. }

  4. func privateFunction() {
  5.    fmt.Println("Hello package")
  6. }
类型
Go 有一个相当简单的类型系统:没有子类型(但有类型转换),没有泛型,没有多态函数,只有一些基本的类型:
1. 基本类型:intint64int8uintfloat32float64 等
2. struct
3. interface:一组方法的集合
4. map[K, V]:一个从键类型到值类型的映射
5. [number]Type:一些 Type 类型的元素组成的数组
6. []Type:某种类型的切片(具有长度和功能的数组的指针)
7. chan Type:一个线程安全的队列
8. 指针 *T 指向其他类型
9. 函数
10.
具名类型:可能具有关联方法的其他类型的别名(LCTT 译注:这里的别名并非指 Go 1.9 中的新特性“类型别名”):
  1.  type T struct { foo int }
  2.  type T *T
  3.  type T OtherNamedType
具名类型完全不同于它们的底层类型,所以你不能让它们互相赋值,但一些操作符,例如 +,能够处理同一底层数值类型的具名类型对象们(所以你可以在上面的示例中把两个 T加起来)。
映射、切片和信道是类似于引用的类型——它们实际上是包含指针的结构。包括数组(具有固定长度并可被拷贝)在内的其他类型则是值传递(拷贝)。
类型转换
类型转换类似于 C 或其他语言中的类型转换。它们写成这样子:
  1. TypeName(value)
常量
Go 有“无类型”字面量和常量。
  1. 1 // 无类型整数字面量
  2. const foo = 1 // 无类型整数常量
  3. const foo int = 1 // int 类型常量
无类型值可以分为以下几类:UntypedBoolUntypedIntUntypedRuneUntypedFloatUntypedComplexUntypedString 以及 UntypedNil(Go 称它们为基础类型,其他基础种类可用于具体类型,如 uint8)。一个无类型值可以赋值给一个从基础类型中派生的具名类型;例如:
  1. type someType int

  2. const untyped = 2 // UntypedInt
  3. const bar someType = untyped // OK: untyped 可以被赋值给 someType
  4. const typed int = 2 // int
  5. const bar2 someType = typed // error: int 不能被赋值给 someType
接口和对象
正如上面所说的,接口是一组方法的集合。Go 本身不是一种面向对象的语言,但它支持将方法关联到具名类型上:当声明一个函数时,可以提供一个接收者。接收者是函数的一个额外参数,可以在函数之前传递并参与函数查找,就像这样:
  1. type SomeType struct { ... }
  2. type SomeType struct { ... }

  3. func (s *SomeType) MyMethod() {
  4. }

  5. func main() {
  6.    var s SomeType
  7.    s.MyMethod()
  8. }
如果对象实现了所有方法,那么它就实现了接口;例如,*SomeType(注意指针)实现了下面的接口 MyMethoder,因此 *SomeType 类型的值就能作为 MyMethoder 类型的值使用。最基本的接口类型是 interface{},它是一个带空方法集的接口 —— 任何对象都满足该接口。
  1. type MyMethoder interface {
  2.    MyMethod()
  3. }
合法的接收者类型是有些限制的;例如,具名类型可以是指针类型(例如,type MyIntPointer *int),但这种类型不是合法的接收者类型。
控制流
Go 提供了三个主要的控制了语句:ifswitch 和 for。这些语句同其他 C 风格语言内的语句非常类似,但有一些不同:
◈ 条件语句没有括号,所以条件语句是 if a == b {} 而不是 if (a == b) {}。大括号是必须的。
◈ 所有的语句都可以有初始化,比如这个 if result, err := someFunction(); err == nil { // use result }
◈ switch 语句在分支里可以使用任何表达式
◈ switch 语句可以处理空的表达式(等于 true
◈ 默认情况下,Go 不会从一个分支进入下一个分支(不需要 break 语句),在程序块的末尾使用 fallthrough 则会进入下一个分支。
◈ 循环语句 for 不仅能循环值域:for key, val := range map { do something }
Go 协程
关键词 go 会产生一个新的 Go 协程goroutine,这是一个可以并行执行的函数。它可以用于任何函数调用,甚至一个匿名函数:
  1. func main() {
  2.    ...
  3.    go func() {
  4.        ...
  5.    }()

  6.    go some_function(some_argument)
  7. }
信道
Go 协程通常和信道channels结合,用来提供一种通信顺序进程的扩展。信道是一个并发安全的队列,而且可以选择是否缓冲数据:
  1. var unbuffered = make(chan int) // 直到数据被读取时完成数据块发送
  2. var buffered = make(chan int, 5) // 最多有 5 个未读取的数据块
运算符 <- code=""> 用于和单个信道进行通信。
  1. valueReadFromChannel := <- span=""> channel
  2. otherChannel <- span=""> valueToSend
语句 select 允许多个信道进行通信:
  1. select {
  2.    case incoming := <- span=""> inboundChannel:
  3.    // 一条新消息
  4.    case outgoingChannel <- span=""> outgoing:
  5.    // 可以发送消息
  6. }
defer 声明
Go 提供语句 defer 允许函数退出时调用执行预定的函数。它可以用于进行资源释放操作,例如:
  1. func myFunc(someFile io.ReadCloser) {
  2.    defer someFile.close()
  3.    /* 文件相关操作 */
  4. }
当然,它允许使用匿名函数作为被调函数,而且编写被调函数时可以像平常一样使用任何变量。
错误处理
Go 没有提供异常类或者结构化的错误处理。然而,它通过第二个及后续的返回值来返回错误从而处理错误:
  1. func Read(p []byte) (n int, err error)

  2. // 内建类型:
  3. type error interface {
  4.    Error() string
  5. }
必须在代码中检查错误或者赋值给 _
  1. n0, _ := Read(Buffer) // 忽略错误
  2. n, err := Read(buffer)
  3. if err != nil {
  4.    return err
  5. }
有两个函数可以快速跳出和恢复调用栈:panic() 和 recover()。当 panic() 被调用时,调用栈开始弹出,同时每个 defer 函数都会正常运行。当一个 defer 函数调用 recover()时,调用栈停止弹出,同时返回函数 panic() 给出的值。如果我们让调用栈正常弹出而不是由于调用 panic() 函数,recover() 将只返回 nil。在下面的例子中,defer 函数将捕获 panic() 抛出的任何 error 类型的值并储存在错误返回值中。第三方库中有时会使用这个方法增强递归代码的可读性,如解析器,同时保持公有函数仍使用普通错误返回值。
  1. func Function() (err error) {
  2.    defer func() {
  3.        s := recover()
  4.        switch s := s.(type) {  // type switch
  5.            case error:
  6.                err = s         // s has type error now
  7.            default:
  8.                panic(s)
  9.        }
  10.    }
  11. }
数组和切片
正如前边说的,数组是值类型,而切片是指向数组的指针。切片可以由现有的数组切片产生,也可以使用 make() 创建切片,这会创建一个匿名数组以保存元素。
  1. slice1 := make([]int, 2, 5) // 分配 5 个元素,其中 2 个初始化为0
  2. slice2 := array[:] // 整个数组的切片
  3. slice3 := array[1:] // 除了首元素的切片
除了上述例子,还有更多可行的切片运算组合,但需要明了直观。
使用 append() 函数,切片可以作为一个变长数组使用。
  1. slice = append(slice, value1, value2)
  2. slice = append(slice, arrayOrSlice...)
切片也可以用于函数的变长参数。
映射
映射maps是简单的键值对储存容器,并支持索引和分配。但它们不是线程安全的。
  1. someValue := someMap[someKey]
  2. someValue, ok := someMap[someKey] // 如果键值不在 someMap 中,变量 ok 会赋值为 `false`
  3. someMap[someKey] = someValue

via: https://blog.jak-linux.org/2018/12/24/introduction-to-go/

Comments

Popular posts from this blog

CKA Simulator Kubernetes 1.22

  https://killer.sh Pre Setup Once you've gained access to your terminal it might be wise to spend ~1 minute to setup your environment. You could set these: alias k = kubectl                         # will already be pre-configured export do = "--dry-run=client -o yaml"     # k get pod x $do export now = "--force --grace-period 0"   # k delete pod x $now Vim To make vim use 2 spaces for a tab edit ~/.vimrc to contain: set tabstop=2 set expandtab set shiftwidth=2 More setup suggestions are in the tips section .     Question 1 | Contexts Task weight: 1%   You have access to multiple clusters from your main terminal through kubectl contexts. Write all those context names into /opt/course/1/contexts . Next write a command to display the current context into /opt/course/1/context_default_kubectl.sh , the command should use kubectl . Finally write a second command doing the same thing into ...

OWASP Top 10 Threats and Mitigations Exam - Single Select

Last updated 4 Aug 11 Course Title: OWASP Top 10 Threats and Mitigation Exam Questions - Single Select 1) Which of the following consequences is most likely to occur due to an injection attack? Spoofing Cross-site request forgery Denial of service   Correct Insecure direct object references 2) Your application is created using a language that does not support a clear distinction between code and data. Which vulnerability is most likely to occur in your application? Injection   Correct Insecure direct object references Failure to restrict URL access Insufficient transport layer protection 3) Which of the following scenarios is most likely to cause an injection attack? Unvalidated input is embedded in an instruction stream.   Correct Unvalidated input can be distinguished from valid instructions. A Web application does not validate a client’s access to a resource. A Web action performs an operation on behalf of the user without checkin...