Go 入门

1. hello,world

hello,world

hello,world

经典示例

package main

import "fmt"

func main() {

    fmt.Println("你好,Go")

}

Go 基础知识 Go 是编译型的语言
Go 的工具链将程序的源文件转变成机器相关的原生二进制指令

这些工具可以通过单一的 go 命令配合其子命令进行使用;

最简单的子命令是 run ,go run 将一个或多个以 " .go " 为后缀的源文件进行编译 、

链接,然后直接运行生成的可执行文件

go run 子命令有点类似 Python 的执行,但实际上是生成可执行文件,但执行后不保留可执行文件

// 执行示例

$ go run hello.go

$ 你好,Go

Go 原生地支持 Unicode,所以 Go 语言可以处理所有国家的语言

使用 go build 命令来将源文件编译成一个可执行文件(二进制程序)

不用进行任何其他处理,随时执行

$ go build -o a.out ./helloworld.go  // -o 指定生成的可执行文件名

$ ./a.out

$ 你好,Go

Go 代码结构

package 声明

Go 代码是使用包来组织的

包,类似于其他语言中的库和模块

一个包由一个或多个 '.go' 源文件组成,放在一个文件夹中

该文件夹的名字描述了包的作用

每一个源文件的开始,都用 package 进行声明

例子中是 package main ,指明了当前文件属于哪个包

package 声明的后面,紧跟着当前文件要导入的其他包的列表

接下来才是存储在文件中的程序声明

Go 标准库

简介

Go 的标准库中有 100 多个包用来完成输入 、输出 、排序 、文本处理等常规任务;

例如,fmt 包中的函数用来格式化输出和扫描输入;

Println 是 fmt 包中一个基本的输出函数,它输出一个或多个用空格分隔的值结尾使用一个换行符,这样看起来这些值是单行输出

main 包

main 函数

名为 main 的包比较特殊,是用来定义一个独立的可执行程序,而不是库
在 main 包中,函数 main 也是特殊的,不管在什么程序中,函数 main 做什么事情,main 函数总是程序开始执行的入口
当然,main 函数通常调用其他包中的函数来做更多的事情,比如 fmt.Println

import 声明

导入工具包

我们需要告诉编译器,源文件需要哪些包,用 package 声明后面的 import 声明,

来导入这些包

必须精确地导入所需要的包
缺失导入包或导入了未使用的包,这两种情况,都会造成编译后失败
这种严格的要求可以防止程序演化中引用不需要的包
import 声明必须跟在 package 声明之后
源文件结构

import 导入声明后面,是组成程序的 函数(func)、变量(var)、

常量(const)、类型(type)的声明

在大部分情况下,上面这些函数 、变量 、常量 、类型的声明的顺序没有特别的要求
函数声明 一个函数的声明由 func 关键字 、函数名 、参数列表(main 函数为空)、返回值列表(可以为空)、被包裹在 '{ }' 中的函数体组成,函数体定义了函数的功能
不以分号结尾

Go 不需要在语句或声明后面使用分号结尾;

除非有多个语句或声明出现在同一行,则语句或声明之间用分号隔开(不建议)

换行解析

事实上,跟在特定符号后面的换行符被转换为分号,在什么地方进行换行会影响对

Go 代码的解析

例如," { " 符号必须和关键字 func 在同一行,不能单独成行;在 x + y 这个表达式中,换行符可以在 + 操作符的后面,但不能在 + 操作符的前面
Go 对于代码的格式化要求非常严格
gofmt 工具将代码以标准格式重写,go 工具的 fmt 子命令使用 gofmt 工具来格式化指定包里的所有文件或者当前文件夹中的文件(默认情况下)
本书中包含的所有 Go 源代码文件都使用 gofmt 运行过,应该养成对自己的代码使用 gofmt 工具的习惯
定制一个标准的格式,可以省去大量无关紧要的辩论;更重要的是,如果允许随心所欲的格式,各种自动化的源代码转换工具将不可用
许多文本编辑器可以配置为每次在保存文件时自动运行 gofmt ,因此源文件总可以保持正确的形式

此外,一个相关的工具 goimports 可以按需管理导入声明的插入和移除;

此工具不是标准发布版的一部分,可以通过执行下面的命令获取到:

$ go get golang.org/x/tols/cmd/goimports

对大多数用户来说,按照常规方式下载 、编译包,执行自带的测试,查看文档等操作,使用 go 工具都可以实现

2. 命令行参数

命令行参数
背景

大部分程序处理输入,然后产生输出,这就是关于计算的大致定义;

但是程序怎样获取数据的输入呢?

一些程序自己生成数据,更多的时候,输入来自一个外部源:

文件 、网络连接 、其他程序的输出 、键盘 、命令行参数等 ...

命令行参数

概览

os  包提供了一些函数和变量,以一种 "与平台无关" 的方式和操作系统打交道

命令行参数以 os 包中的 Args 名字的变量供程序访问;

在 os 包外面,使用名字 os.Args ( import "os" )

变量 os.Args 是一个字符串 slice ;

os.Args[ i ] 获取单个命令行参数(char *argv[]) ;

len(os.Args) 得到命令行参数总的数量(int argc) ;

os.Args 是一个切片,第一个元素是 os.Args[0] ,它是命令(可执行文件)本身的名字 

另外的元素是程序开始执行时的参数

表达式 s[m:n] 表示一个从第 m 个到第 n-1 个元素的 slice ;

如果 m 缺失,默认值为 0 ;如果 n 缺失,默认值为 len(s) ;

所以可以将期望的 slice 简写成 os.Args[1: ]

切片概览

slice 是 Go 中的基础概念,当前只需将其作为一个动态容量的顺序数组 s ;

可以通过 s[ i ] 来访问单个元素 ;

通过 s[ m : n ] 来访问一段连续子区间 ;
数组长度用 len( s ) 表示 ;

与大部分编程语言一样,在 Go 中,所有的索引使用前闭后开区间

即包含第一个索引,不包含最后一个索引,因为这样逻辑简单(参考 Python 切片语法)

例如,s[ m : n ] 这个子序列,包含元素 s[m] ,但不包含元素 s[n]

知识点:

导入多个包

这里有一个 UNIX echo 命令的实现,它将命令行参数输出到一行;

该实现导入两个包,使用由圆括号括起来的列表,而不是独立的 import 声明;两者都是合法的;导入的顺序是没有关系的,gofmt 工具会将其按照字母顺序表进行排序

代码示例1

// echo1 输出其命令行参数

package main 

// import "fmt"

// import "os"

import (

        "fmt"

        "os"

)

func main() {

        var  s ,sep  string  

        for  i  :=  1;i  <  len(os.Args);i++  {

                s  +=  sep  +  os.Args[ i ]

                sep  =  " "

        }

        fmt.Println( s )

}

注释

注释以  //  开头

所有以  //  开头的文本是给程序员看的注释,编译器将会忽略这些文本

习惯上,在一个包声明(package 声明)前,使用注释对其进行描述

对于 main 包,注释是一个或多个完整的句子,用来对这个程序进行整体概括

变量声明

及初始化

// var 关键字声明了两个 string 类型的变量 s 和 sep

变量可以在声明的时候初始化;

如果变量没有明确地初始化,变量会初始化为这个类型的空值(零值)

数字初始化为 0 ,字符串初始化为 "" ,

对于数字,Go 提供了常规的算术和逻辑操作符;

当应用于字符串时,+ 操作符对字符串的值进行追加操作,所以表达式

        sep + os.Args[ i ]

表示将  sep  和  os.Args[ i ] 追加到一起;程序中使用的语句

        s  +=   sep  +  os.Args[ i ]

是一个赋值语句,将  sep  和  os.Args[ i ] 追加到旧的  s  上面,并重新赋给 s ,等价于下面的语句 :

        s  =  s  +  sep  +  os.Args[ i ]

操作符  +=  是一个赋值操作符;

每一个算术和逻辑操作符(例如 * 或者 +)都有一个对应的赋值操作符

代码说明

echo 程序会循环每次输出,但是这个版本中,我们通过反复追加来构建一个字符串;

字符串 s 一开始为空字符串 "" ,每一次循环追加一些文本;在第一次迭代后,一个空格被插入,这样当循环结束时,每个参数之间都有一个空格;这是一个二次过程,如果参数数量很大成本会比较高,不过对于 echo 程序还好

接下来会展示几个改进版本,它们会逐步处理掉低效的地方

循环的索引变量 i 在 for 循环开始处声明;

:=  符号用于 " 短变量声明 " ,这种语句声明一个或多个变量,并且根据初始化的值给予合适的类型(根据值推导出类型)

递增语句 i++ 对 i 进行加 1 ,和下面两者写法等价

        i += 1

        i = i + 1

对应的递减语句 i-- 对 i 进行减 1

在 Go 中,++/-- 是语句,不像其他类 C 语言一样是表达式,所以 j = i++ 是不合法的

Go 语言只支持 "k++" 和 "k--" ,不支持 "++k" 和 "--k" 

for 循环
for 循环是 Go 里面的唯一循环语句,分为传统 for 循环和迭代 for 循环
传统 for

//  经典 for 循环

for  initialization;condition;post {

}

for 循环的三个组成部分两边不用圆括号;

语句块必须用花括号括起来,哪怕只有一条语句;左花括号必须和 post(后置)语句在同一行

可选的 initialization(初始化)语句在循环开始之前执行;如果初始化语句存在,它必须是一个简单的语句,比如一个简短的变量声明,一个递增或赋值语句,或者一个函数调用

condition(条件)是一个布尔表达式,在循环的每一次迭代开始前判断,如果判断结果为真,循环继续执行,判断条件为假,立刻结束循环

post 语句在循环体(花括号括起来的所有语句)之后被执行,然后 condition 被再次判断;判断结果为假则立刻结束循环

三个部分都是可以省略的

如果没有 initialization 和 post 语句,分号可以省略:

// 传统的 "while" 循环

for condition {

        // ...

}

如果条件部分都不存在:

// 无限循环 ,可以通过 break 或 return 终止循环

for {

        // ...

}

迭代 for

另一种形式的 for 循环在字符串或 slice 数据上迭代,迭代 for 循环

// echo2 输出其命令行参数

package main

import (

        "fmt"

        "os"

)

func main() {

        s,sep  :=  "",""

        for  _,arg  :=  range  os.Args[1 : ]  {

                s  +=  sep  +  arg

                sep  =  " "

        }

        fmt.Println( s )

}

// C++

for (auto c : str) {

    cout << c << endl;

}

每一次迭代,range 产生一对值 :索引和这个索引处元素的值(下标 、元素值)
在这个例子里,我们不需要

3. 找出重复行

4. GIF 动画

5. 获取一个 URL

6. 并发获取多个 URL

7. 一个 Web 服务器

8. 其他内容

你可能感兴趣的:(后端编程语言,golang)