实践选题:Go语言入门指南 | 青训营

144 阅读5分钟

GO语言基础

  • 高性能,高并发
  • 丰富的标准库和完整的工具链
  • 静态链接
  • 快速编译
  • 跨平台(各种操作系统,树莓派等)
  • 垃圾回收(无需考虑内存分配释放)

基础语法

变量命名与赋值

  • 常量可以不显式指定数据类型,编译器可以根据上下文自动确定
var a = 1
var b int = 2

注意!!!在Go语言中赋值有两种方法:=和:=,其中=只是单纯的赋值,而:=表示声明并赋值,如果变量先前已经声明,则可以直接使用=,否则需使用:=。

条件控制语句

if语句

语法格式如下:

if <bool> {
​
} else if <bool> {
​
} else{
​
}

注意,if后面的bool语句不用打括号,并且else ifelse必须写在上一个大括号的同一行(??)

for语句

在GO语言中,没有while和do while语句,只有for语句,for语句可以缺省任何一部分值,例如

for {
    //表示死循环
}
for i:=1;i<10;i++ {
    //从1-9的遍历
}

switch语句

switch a{
    case 1:
    case 2:
    default:
}

GO语句在switch之后不需要加break手动破坏,即每次只会执行一个结果。

switch可以使用任意的数据结构,比如

t := time.Now()
switch {
    case t.Hour()<12:
    default:
}

数组与切片

数组

数组长度是固定的,具有内置的操作函数。

var arr [5]int
fmt.Println(arr[0],len(a))

切片

有点类似Vector,但是不是一个对象len和append函数不能直接使用'.'获取,长度可变的数组,实现方法如下

s := make([]string,3)
fmt.Println(s[0],len(s));
s=append(s,'f')
​
//选择数组长度的方法
fmt.Println(s[1:5])
fmt.Println(s[:5])
fmt.Println(s[1:])

Map键值对

也就是其它语言中的哈希(HashMap)等数据结构,定义方法如下:

m := make(map[string]int)

range

在不关心某个切片或者数组索引的时候,可以直接遍历里面的元素,写法如下:

nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
    sum += num
}
fmt.Println("sum:", sum)

函数

基本形式为func (结构体示例) <函数名> (函数参数) <返回类型>,具体看结构体方法部分的代码,有给出两种不同的函数体的定义。

指针

//Go语言的指针使用比较简单,就是C++中的指针传递方法,可以用于在函数中修改指针的值,比如
func test(str *string) string{
    return str+"。"
}

结构体

//结构体声明
type user struct{
    name string
    psw string
}
​
//结构体初始化
a:=user(name:"Veni",psw:"1111")
a:=user("Veni","1111")

结构体方法

结构体方法类似C++中的类成员函数,定义方法:

//非结构体方法的函数定义:
func checkPassword(u user,password string) bool{
    return u.password==password
}
​
//结构体方法的函数定义
func (u user) checkPassword(password string) bool{
    return u.password==password
}
fmt.Println(a.checkPassword("1111"))//return true or false

错误处理

在函数返回值的时候可以定义返回值err,同时return两个值,比如

func findUser(users []user,name string)(v *user,err error){
    for _,u :=range users{
        if(u.name==name){
            return &u,nil
        }
    }
    return nil,error.New("Not Found")
}

字符串函数

OJ必备,用好了可以提高效率

字符串操作函数

import{
    "strings"
}
​
func main(){
    a:="hello"
    strings.Contains(a,"ll")//true
    strings.Count(a,"l") //2
    strings.HasPrefix(a,"he")//true
    strings.HasSuffix(a."llo")//true
    strings.Index(a,"ll")//2
    strings.Repeate(a,2)//hellohello
    strings.Replace(a,"e","E",-1)//hEllo
    strings.Split("a-b-c","-")//[a b c]
    strings.ToLower(a)//hello
    strings.ToUpper(a)//HELLO
}

字符串格式化

fmt.Printf("s=%v\n",p) //%v可以是任意类型的占位符
fmt.Printf("s=%+v\n",p)
fmt.Printf("s=%#v\n",p) //更加详细的信息
fmt.Printf("s=%.2f\n",3.1415)

数字解析

引入strconv包

n,_ :=strconv.ParseInt("111",10,64)
​
n1,_ :=strconv.Atoi("111")

Json操作

只需要定义一个结构体,结构体的首字母需要大写,之后就可以直接进行序列化。

type userInfo struct{
    Name string
    Age int `json:"age"` //将字段名改成小写的age,一般不加这一段
    Hobby []string
}
​
//序列化
buf,err :=json.Marshal(a)
jmt.Println(string(buf)) //打印json,记得加string,不然会打印出一堆十六进制编码//反序列化
var b userInfo
err=json.Unmarshal(buf,&b)

时间处理

需要import time,可以直接查文档。最常用的是获取当前时间:

t:=time.Now()

进程信息

使用GO语言可以查看进程的相关信息,具体可以查看文档。

输入输出

输入的几种方法

使用fmt包

  • 格式化扫描输入
// 从 控制台(os.Stdin) 扫描输入
var a int
fmt.Scan(&a)                                // 输入: 123<回车>
fmt.Println(a)                              // 输出: 123var b int
var s string
fmt.Scan(&b, &s)                            // 输入: 123 Hello<回车>
fmt.Println(b, s)                           // 输出: 123 Hello// 从 字符串(string) 扫描输出
fmt.Sscan("456", &a)
fmt.Println(a)                              // 输出: 456
​
fmt.Sscan("456 World", &b, &s)
fmt.Println(b, s)                           // 输出: 456 World
  • 格式化扫描输入
// 从 控制台(os.Stdin) 格式化扫描输入
var a int
fmt.Scanf("%d", &a)                         // 输入: 123<回车>
fmt.Println(a)                              // 输出: 123var b int
var s string
fmt.Scanf("%d%s", &b, &s)                   // 输入: 123 Hello<回车>
fmt.Println(b, s)                           // 输出: 123 Hello// 从 字符串(string) 格式化扫描输出
fmt.Sscanf("456", "%d", &a)
fmt.Println(a)                              // 输出: 456
​
fmt.Sscanf("456 World", "%d%s", &b, &s)
fmt.Println(b, s)                           // 输出: 456 World

事实上,%d%s只是用来格式化的一个占位符,在GO语言中可以使用%v代替,没怎么写过C语言的选手也可以用好Scanf啦!

从标准输入(os.Stdin)直接读取数据

// 创建 字节切片 用于保存读取到的字节序列
buf := make([]byte, 10)
​
// 等待从 控制台(os.Stdin) 输入数据, 按回车键触发读取,
// 最多读取 len(buf) 个字节, 
// 回车符(\n)也算作是输入的数据, 也会被读取,
// 读取的字节序列是经过 UTF-8 编码的字节序列,
// 返回的 n 表示本次读取的字节数
n, err := os.Stdin.Read(buf)
fmt.Println(n, err)
​
// 转换为字符串输出
fmt.Printf("%s", string(buf[:n]))
​

使用bufio.Scanner扫描器读取数据

// 创建一个扫描器对象, 从 os.Stdin 中扫描数据
scan := bufio.NewScanner(os.Stdin)
​
// 阻塞等待输入, 输入数据后, 按回车触发扫描, Scan() 返回 true
if scan.Scan() {
    // 以 (UTF-8)字符串 的形式读取本次扫描的数据 (支持输入空格, 不包括换行符, 换行符自动舍去)
    s := scan.Text()
    fmt.Printf("%s\n", s)
}
​
// 继续阻塞等待下次输入
if scan.Scan() {
    // 以 (UTF-8)字节切片 的形式读取本次扫描的数据
    b := scan.Bytes()
    fmt.Printf("%s\n", string(b))
}

字节训练营中的一段bug码,在这段代码中会读取换行符和回车键\r\n,需要手动去除。

reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil {
    fmt.Println("输入错误,请重新输入")
    return
}
input = strings.Trim(input, "\r")
input = strings.Trim(input, "\n")

一般的输入输出还是用Scan好一点,如果做OJ写成上面那样真的会疯掉。