【go】gopl学习笔记(1.语言基础)

这篇博客是关于Go语言的学习笔记,涵盖了程序结构、数据类型,包括基础类型(整型、字符串)和复合类型(数组、Slice、Map、Struct)。文章强调了Go语言的类型转换规则、字符串特性和复合类型的行为,特别是Slice作为栈或队列的使用,以及Map和Struct的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了加快阅读gopl(The Go Programming Language)书效率,决定输出笔记+leet实战以督促自己,加快速度、提升效果

1 程序结构

一个可执行程序如下,入口是main包下的main.go 文件中的main函数,包之间有依赖关系,编译器解析依赖时会递归地加载其依赖地包,所以在main函数之前,加载main包,递归加载main包所依赖的包如fmt,fmt又依赖别的C,会递归地加载C,是个DFS的过程,这样就加载了所有需要的包。

每个go文件包含以下几个元素

结构组成语义包含组件样例
package声明所在package

-

package main

import引入依赖的包-

import fmt 

import (

"fmt"

"math"

"os"

)

var声明包级变量-

var count int

var (

width, height = 600, 320

cells = 100

)

const声明包级常量-
const name=xxx
const (
   width, height = 600, 320           
   cells         = 100 
)
type

类型声明

类型重命名

-

type name int64

声明struct等自定义类型 

type Circle struct {

     Point Radius int

}

func

声明包级函数或方法

 

函数签名 

  • [类型引用] (方法特有)
  • 函数名
  • 参数列表
  • [返回值(多)]
函数
func comma(s string) string {

方法

func (p Point) Distance(q Point) float64 {

函数体

  • var
  • const
  • [for]
  • [if]
  • [switch]
  • [return]

var name type 

cwd,err := os.Getwd() //短格式变量声明

const name type

for 无小括号

for i := 1; i < len(os.Args); i++ {
    fmt.Printf("  %s\n", comma(os.Args[i]))
}

if无小括号

if err != nil {
    fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
}

if _, err := io.Copy(dst, src); err != nil {// 带简易赋值语句
    log.Fatal(err)
}

switch unit {
case "C", "°C":
    f.Celsius = Celsius(value)
    return nil
case "F", "°F":
    f.Celsius = FToC(Fahrenheit(value))
    return nil
}

2 数据类型

与其它语言类似,分为基础类型和组合符合,不同的是Go不能隐式类型转换,如JAVA中会在数值操作时,自动将类型提升,如long类型和int类型是可以相加的,在计算之前会先将int类型提升到long类型再计算。而Go需要显式强制转换才可以进行算术操作或者比较等,否则编译报错。

2.1 基础类型

以上基础数据类型中最常用是字符串和整型,

2.1.1 整型

分为有符号和无符号两种,有符号和无符号又分为通用类型和细化到多少字节的类型,如int8、uint16等等。

需要注意的是,int8和int16两种类型的变量之间是不能做算术操作的,此时需要做强制转换,一般转化为通用类型。

Java语言中的byte类型此处可以对标unit8

2.1.2 字符串

与java不同的是,go的string的零值空串"",而不是nil

数据

底层表示是个utf-8编码的字节数组,如下表和图。

fmt.Println(reflect.TypeOf('[')) // int32
fmt.Println(reflect.TypeOf('王'))// int32, Unicode编码?

操作

操作含义
len(s)len函数获取底层字节数组uint8[]长度
RuneCountInString(s)

按utf8解码后的字符长度

unicode/utf8包

s[i]取字节,返回 uint8
s[0:5]切片
转换
    

y := fmt.Sprintf("%d", x)

strconv.Itoa(x) 整形转化字符串,类似Java的String.valueOf(int)

strconv.FormatInt(int64(x), 2))  //转二进制字符串

strconv.Atoi("123")  字符串转整型

string(65) utf8码值转string
b :=[]byte(s) 串转字节数组 类似于String的getBytes(),返回拷贝

s:=string(b)  字节数组->字符串

迭代

类似于遍历一个数组,遍历的是字符,不是字节哦

for i := range astr {
    strmap[astr[i]]++
}

for i := 0; i < len(s); i++ {

if HasPrefix(s[i:], substr) {

return true

}

}

常用类库

package功能
stringssearch搜索、replace替换、compare比较、trim、split切分、join连接
bytes

bytes.Buffer

类似Java的StringBuffer用于多次连接,防止不可变string拼接效率地下

strconv转化bool、int、float等
unicode

IsDigit, IsLetter, IsUpper,ToUpper and ToLower

2.2 复合类型

复合类型声明定义&初始化获取写入遍历比较
数组
var a [3]int // 零值初始化
var q [3]int = [3]int{1, 2, 3} // init
q := [...]int{1, 2, 3}//omit len
d := [3]int{1, 2} // 部分初始化
r := [...]int{99: -1} // 指定下标初始化[]byte("x")
a[0]
a[i,j] 切片子序列
a[0] = 1

for i, v := range a {...}

for i := range a {...}

for _, v := range a { ... }

==

逐一比较元素

Slice
var runes []rune // nil
s := []int{0, 1, 2, 3, 4, 5} // 没长度,也没...
Q2 := months[4:7]
make([]T, len)
make([]T, len, cap)
make([]T, cap)[:len]

同上

可以超出len,

但不能超出cap

同上

append

同上

summer == nil 其余不能==

len(s) == 0叛空

bytes.Equal([]byte,[]byte)

Map

var ages map[string]int   // nil

map[string]int{} //empty map

ages := make(map[string]int)

ages := map[string]int{

"alice": 31,

"charlie": 34,

}

ages["charlie"]

不含key,返回零值

age, ok := ages["bob"] // 判断是否成功

不能获取元素地址

ages["charlie"] = 34

形式同上,key类型不同

 

同slice

Struct

type Point struct{ X, Y int }

p := Point{1, 2}

anim := gif.GIF{LoopCount: nframes}

p.X

x := &p.X

p.X = 5000

 

== or !=.

Json

data, err := json.Marshal(movies)

将结构体转化给字节数组 序列化MarshalIndent

Unmarshal 反序列化

    

2.2.1 数组

定长同构序列。

定义和使用大多类似其它语言,与JAVA不同的是调用函数传参数组时是传递的copy,所以在函数内修改数组内容对于调用者并不可见,为了提升效率或者修改可见,需要使用显式指针传递,所以我们通常不用数组做为函数的参数,通常传入切片,切片允许函数内修改。

func zero(ptr [3]int) {
	for i := range ptr {
		ptr[i] = 0
	}
}

func zero2(ptr *[3]int) {
	for i := range ptr {
		ptr[i] = 0
	}
}

func main() {
	d := [3]int{1, 2}
	fmt.Println(d) // [1 2 0]
	zero(d) // 并不能修改原数组 传递copy
	fmt.Println(d) // [1 2 0]
	zero2(&d)
	fmt.Println(d)  // [0 0 0]
}

2.2.2 Slice

变长同构序列,底层是数组,是数组的一个切片,语法与字符串的substring语法类似,arr[i:j]

以下面为例,months是一个定长数组[13]string,months[i:j]是一个切片[]string,切片包含起始指针、长度、容量;

func main() {
	months := [...]string{1: "Jan", 2:"Feb", 3:"mar", 4:"apr", 5:"may", 6:"june", 7:"july", 8:"august", 9:"sep", 10:"oct", 11:"nov", 12: "December"}
	Q2 := months[4:7]
	summer := months[6:9]
	fmt.Printf("%T\n", Q2)
	fmt.Println(Q2) // ["April" "May" "June"]
	fmt.Printf("%T\n", summer)
	fmt.Println(summer) // ["June" "July" "August"]
}

 

常用lib操作

rotate, reverse, 

可用做stack栈数据结构,也可用作队列

stack = append(stack, v) // push v
top := stack[len(stack)-1] // top of stack
stack = stack[:len(stack)-1] // pop

2.2.3 Map

k-v 无序集合,k的类型限制是必须能使用== 判断key是否相等,如果想用不支持==的类型做key,如slice,可以将其转换成string再做key。Go没有提供set类型,由map提供类似功能(map[string]bool)

2.2.4 Struct

异构聚合类型,包含一系列不同类型的字段,类似C的结构体,与之不同的是,go结构体的指针p引用字段不一样,C是*p.field或者p->field,而go的直接是p.field,与(*p).field等同。

同样是值传递,如需在函数体内修改,需要传递指针。

嵌套组合

还有个重要的特性,嵌套机制,类似于Java的组合,一个结构体可以包含另一个结构体类型的字段,此外还有匿名机制(语法糖),可以缩短引用链的长度,如下例的 一个轮子包含一个圈,一个圈包含一个圆心(Point),当引用圆心的x坐标时,链w.Circle.Point.X特别长,当使用匿名字段(默认是类型名),就可以用w.X引用了。但是字面量{}初始化时不能这样使用。

type Point struct {
	X int
	Y int
}
type Circle struct {
	Point
	Radius int
}
type Wheel struct {
	Circle
	Spokes int
}
var w Wheel
w.X = 8 //  w.Circle.Point.X = 8
w.Y = 8 //  w.Circle.Point.Y = 8
w.Radius = 5 //  w.Circle.Radius = 5
w.Spokes = 20
fmt.Println(w)

new 和 make 均是用于分配内存:new 用于值类型和用户定义的类型,如自定义结构,make 用于内置引用类型(切片、map 和管道)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值