前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >GoLang 最佳实践超全版【一】

GoLang 最佳实践超全版【一】

作者头像
饶文津
发布于 2022-05-11 02:23:41
发布于 2022-05-11 02:23:41
79600
代码可运行
举报
文章被收录于专栏:饶文津的专栏饶文津的专栏
运行总次数:0
代码可运行

一、入门

二、初始化

展开

  1. 常量
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type ByteSize float64

const (
    _            = iota //  iota 是枚举器(0 开始,每行+1),用 _ 忽略第一个值
    KB ByteSize  = 1 << (10 * iota)
    MB
    GB
)
  1. 变量
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
x := 10
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var (
    home = os.Getenv("HOME")
    user = os.Getenv("USER")
)
  • 如果左边多个变量,可以有已经定义过的变量(同一作用域里),但必须至少有一个是未定义过的。对于已经定义过的变量就是赋值操作。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var err error.Error
res, err := get()
  • 如果是在全局区域,只能用 var 初始化,不能用 :=
  • 会让可读性变差、带来意料之外的副作用。
  • 最好是提供相应初始化函数给调用者来避免使用init。
  • 避免I/O调用(单元测试时不希望有)、避免依赖其它的 init() 函数、避免修改全局函数、环境状态。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func init() {
    这里执行的代码会在当前包被 import 时执行。
}

三、数据

展开

1. 基本类型
  • int int8 int16 int32 int64
  • uint uint8 uint16 uint32 uint64 uintptr
  • bool string byte(uint8别名) rune(int32 别名)
  • float32 float64 complex64 complex128
2. 结构体

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 这样初始化拿到的是该类型的零值的指针,里面每个属性都是对应类型的零值
f := &File{} 或 f := new(File)
f.fd = fd
f.name = name

// 填写每个属性
f := &File{fd, name, nil, 0}

// 通过 label 可以只赋值部分属性
f := &File{fd: fd, name: name}
3. array 和 slice

展开

  1. array 的定义方式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
a := [100]int{}
var b [10]int
c := [...]int{1, 2, 3}
  1. slice 的定义方式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s := make([]int, 100)
var nums []float
  1. 二维数组/切片
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var s [][]byte

// 定义了一个 5 行 8 列的数组
picture := make([][]uint8, 5)
for i := range picture {
    picture[i] = make([]uint8, 8)
}
  1. 可以通过 type 定义一个类型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type LinesOfText [][]byte
text := LinesOfText{
    []byte("good"), 
    []byte("gophers"),
}
  1. 整体赋值
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 数组整体赋值是拷贝
a := [1]int{1}
b := a // 此时 a 和 b 不是同一个数组
b[0] = 2 // a = [1], b = [2]

// slice 的整体赋值是指向同一个底层数组
s := []int{1}
t := s
t[0] = 2 // s = [2], t = [2]
  1. 切片操作

起点可以省略,不能像 python 一样用负数。切片底层指向同一块空间。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s := a[1:3]
prefix := str[:len(str)-10]
  1. 完整的切片表达式

代表容量(cap)为 max-low,容量会影响 append 操作的具体实现。字符串不适用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
a[low : high : max]
4. map

展开

  1. 定义与使用
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var timeZone = map[string]int{
    "UTC": 0,
    "CST": -6,
    "PST": -8,
}

timeZone["MST"] // 0,不存在的 key,会得到 value 类型的零值。
t, ok := timeZone["MST"] // 会得到 0, false
if _, ok := timeZone["MST"]; ok { // 如果只是判断是否存在

delete(timeZone, "UTC") // 删除某个 key
  1. Map 的 value 存的是值,会发生 copy,所以一般用指针类型。
  2. Map 的 key 不应用指针类型,否则值相同也是不同 key。
  3. slice、function、map 类型不能作为 map 的 key。
  4. 不能对 map 的 value 进行取地址,因为一扩容地址就变了。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
&timeZone["UTC"] // 是错误的, cannot take address of timeZone["UTC"]
  1. 不能对 map 的值的字段修改,除非是指针类型。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
myMap := map[string]Point{"origin": {x: 0, y: 0}}
myMap["origin"].x = 3 // 是错误的。cannot assign to struct field .. in map

myMap := map[string]*Point{"origin": {x: 0, y: 0}}
myMap["origin"].x = 1 // 是可以的
  1. map 不支持并发读写,只能并发读。并发写回强行退出程序,抛出 fatal error: concurrent map read and map write。
  2. 删除 key 时,Map 不会自动缩容,需要设置为 nil,或是手动调用 gc。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
runtime.GC()
  1. 避免在map 的值中引用大数组
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
name := "/path/to/file"
data, _ := ioutil.ReadFile(name)
myMap[name] = data[:10] // Bad:data 不会被回收
myMap[name] = append([]byte{}, data[:10]...) //  Good:data 会被回收
5. string

展开

  1. 底层实现是一个指向数据的指针和一个长度字段。
  2. String 和 []byte 直接做类型转换会进行拷贝。
  3. 中文的 string 切片或获取长度时应转为 []rune 再使用。
6. set

展开

Go 中没有集合,可以用 map 实现,并用struct{} 作为值,因为它被编译器优化过,指向同一个内存地址,不额外占空间。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type MySet map[int]struct{}

func (s MySet) Add(num int) {
    if s == nil {
        s = make(MySet)
    }
    s[num] = struct{}{}
}

set := MySet{}
set.Add(1)

四、结构

展开

  1. 如果只是 if 里用的变量,尽量写在 if 的初始化里,代码看起来更简洁
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if r, ok := dst.(ReaderFrom); ok {
   return r.ReadFrom(src)
}
  1. for 循环

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for init; condition; post {}

// 相当于 while
for condition {}

// 相当于 for(;;)
for {}

// 可以这样初始化、改变多个变量,但是不能像 C++ 里用`,`划分多个语句。
for i, j := 0, len(a) - 1; i < j; i, j = i+1, j-1 {
    a[i], a[j] = a[j], a[i]
}

// 遍历的是 key
for x := range myMap {}

// 遍历的是 value
for _, v := range myMap {}

// 遍历的是 index
for x := range mySlice {}

// 遍历的是 value
for _, v := range mySlice {}
  1. switch

展开

  1. 可以不根据某个变量的值进行选择,而是从上到下找到第一个为真的表达式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func unhex(c byte) byte {
    switch {
    case '0' <= c && c <= '9':
        return c - '0'
    case 'a' <= c && c <= 'f':
        return c - 'a' + 10
    case 'A' <= c && c <= 'F':
        return c - 'A' + 10
    }
    return 0
}
  1. 不会像 C++ 一样自动进入下一个 case,如果需要可以用 fallthrough 关键字,或者
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
switch c {
case ' ', '?', '&':
    f(c)
}
  1. 使用 label 跳出循环(适用于 for 循环里的 switch、select 代码块)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Loop:
    for {
        r, size := decode(s[i:])
        switch {
        case size == 1 && r == invalidMsg:
            return "", fmt.Errorf("invalid: %q", s) // %q 带双引号

        case size == 0:
            // 跳出 for 循环
            break Loop

        default:
            result += r
        }
        i += size
    }
  1. interface{} 的类型判断
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func f(x int) interface{} {
    switch x {
    case 1:
        return 1
    case 2:
        return "1"
    }
    return nil
}

t = f(1)
switch t := t.(type) {
default:
    fmt.Printf("unexpected type: %T\n", t)
case int:
    fmt.Printf("integer %d\n", t)
case string:
    fmt.Printf("string %s\n", t)
}
}

五、函数

展开

1. 返回多个值

展开

多个返回值需要用括号括起来。 返回值可以有名字,初始值为类型的零值。return 可后面不加内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func Cut(s, sep []byte) (before, after []byte, found bool) {
        if i := Index(s, sep); i >= 0 {
                return s[:i], s[i+len(sep):], true
        }
        return s, nil, false
}
2. 闭包

展开

  1. 引用了函数体外面的变量的函数。也就是这些变量和该函数绑定在一起。

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func adder() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}

pos, neg = adder(), adder()
for i := 0; i < 10; i++ {
    fmt.Println(pos(i), net(-i))
}
  1. for 循环里用闭包的坑(govet 会检测出来)

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for i := 0; i < 100; i++ {
    go func() {
        fmt.Println(i)
    }()
}
select{} // 阻塞

会得到100 个 0-100 中的任意数字。应该改为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go func(num int) {
    fmt.Println(num)
}(i) // 将变量拷贝传进函数

会得到 0-100 的某个排列

另一种方法是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for i := 0; i < 100; i++ {
    ii := i // 局部变量逃逸,指的是编译器会根据实际使用域决定放堆上还是栈上。这里会放到堆上。
    go func() {
        fmt.Println(ii)
    }()
}
3. defer

展开

  1. 常用来解锁、关闭连接、关闭文件描述符、recover panic。

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Contents returns the file's contents as a string.
func Contents(filename string) (string, error) {
    f, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    defer f.Close()  // Close 应该放到 err 判断后面,否则会 panic

    var result []byte
    buf := make([]byte, 100)
    for {
        n, err := f.Read(buf[0:])
        result = append(result, buf[0:n]...) // append is discussed later.
        if err != nil {
            if err == io.EOF {
                break
            }
            return "", err  // f will be closed if we return here.
        }
    }
    return string(result), nil // f will be closed if we return here.
}
  1. 按栈的顺序,先进后出。
  2. 预计算参数

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func f() {
    startedAt := time.Now()
 
    // 这样会立刻计算出函数用到的参数并进行拷贝,而不是执行 defer 时才计算。
    defer fmt.Println("假执行时间: ", time.Since(startedAt))
    
    // 利用闭包。这样拷贝的是函数指针。退出函数 f 时才计算。
    defer func() { fmt.Println("真执行时间: ", time.Since(startedAt)) }()
        
    time.Sleep(time.Second)
}
  1. 注意 defer 属于哪个函数

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func f() {
    for {
        func(..) {
            row, err := db.Query("...")
            if err != nil {
                ..
            }
            defer row.Close() // 这样会在内层函数退出时就执行
            ..
        }(..)
    }
}
  1. 函数也可以作为类型,传参

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func compute(f func(float64, float64) float64) float64 {
    return f(3, 4)
}

add := func(x, y float64) float64 {
    return math.Sqrt(x*x + y*y)
}

compute(add)
4. make

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// slice 的初始化,会有一个容量是 cap,有 len 个 0 (int 的零值)的 int 数组。
s := make([]int, len, cap)

// len 和 cap 相等时可以忽略 cap,这样更简洁
s := make([]int, len)

// map 的初始化
m := make(map[string]string, cap)
  • 对于最大长度确定的时候,初始化 len,通过下标修改值,会比 append 更高效。
5. append

展开

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// append slice。数组不能 append。
func append(slice []T, elements ...T) []T

// 可以 append 多个
s = append(s, 0, 1, 2)

// append 后 len 就是原来的 len 加上新元素个数。
// 扩容逻辑:cap < 1024时,会翻倍增长,否则 1.25 倍。
var s []int
s = append(s, 0) // len 是 1, cap 是 1
s = append(s, 1) // len 是 2, cap 是 2
s = append(s, 2) // len 是 3, cap 是 4
fmt.Println(s) // [0, 1, 2]


func modifySlice(s []int) {
    s = append(s, 3)
    s[0] = -1
}

// 函数都是传值的,slice 的数据结构里包含指向数组的指针、len、cap。
modifySlice(s)
fmt.Println(s) // [-1, 1, 2],append 修改了 cap 和 len 不会作用在这里的 s

六、方法

展开

  1. 可以给结构体定义方法。接收者可以用值或指针。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 不修改函数接收者时,用值作为函数接收者
func (r Response) Code() int {
    return r.code
}

// 修改时,用指针。但是有时为了统一写法,就都用指针。
func (r *Response) SetCode(code int) {
    r.code = code
}

// 使用值接收者的函数可以被指针、值调用。而指针接收者只能被指针调用。
var r *Response
r.SetCode(1)
r.Code()
  1. 为结构体实现 String 方法,方便打印,尤其是带有指针成员的结构体。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Point struct {
    x, y int
}

func (p *Point) String() string {
    return fmt.Sprintf("(%d, %d)", p.x, p.y)
}

myMap := map[string]*Point{"origin": {x: 0, y: 0}}
fmt.Printf("%s", myMap)

七、接口

展开 1. 定义接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Writer interface {
  
}
  1. 一个类型可以实现多个接口。

如下是实现 sort.Interface 接口,需要实现 Len(), Less(), Swap() 函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Sequence []int

// Methods required by sort.Interface.
func (s Sequence) Len() int {
    return len(s)
}
func (s Sequence) Less(i, j int) bool {
    return s[i] < s[j]
}
func (s Sequence) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

// Copy returns a copy of the Sequence.
func (s Sequence) Copy() Sequence {
    copy := make(Sequence, 0, len(s))
    return append(copy, s...)
}

// Method for printing - sorts the elements before printing.
func (s Sequence) String() string {
    s = s.Copy() // Make a copy; don't overwrite argument.
    
    sort.Sort(s)
    // 也可以直接 sort.IntSlice(s).Sort(),就不用自己实现接口了。
    
    return fmt.Sprint([]int(s))
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
JavaSE基础 (全网最全知识点)
一个位也叫一个bit,8个bit称为1字节,16个bit称为一个字,32个bit称为一个双字,64个bit称为一个四字
不吃紫菜
2023/03/08
7480
JavaSE基础 (全网最全知识点)
Java 大神的十个私藏避坑绝技
答案是: No! 看似正确的判断奇数, 但是如果 i 是负数, 那么它返回值都是false 造成这种现象的是 => 从思想上固化, 认为奇数只在正数范围, 故判断负数将报错, 在C++中也是, 负数取余还是负. 在Java中取余操作定义产生的后果都满足下面的恒等式:
大蕉
2019/09/30
1K0
《编写高质量代码》学习笔记(1)
前言 看大神推荐的书单中入门有这么一本书,所以决定把这本书的精华(自认为很有用的点),或许是我自己现在能用到的点都提炼出来,供大家参考学习。 以下内容均出自《编写高质量代码 改善Java程序的151个建议》——秦小波 著一书。 ---- 建议1:不要在常量和变量中出现易混淆的字母 包名全小写,类名首字母全大写,常量全部大写并用下划线分隔,变量采用驼峰命名法命名等,这些都是最基本的Java编码规范,是每个Javaer都应熟知的规则,但是在变量的声明中药注意不要引入容易混淆的字母。看下面的例子,请思考以下程序
我没有三颗心脏
2018/04/26
1.4K0
【计组不挂科】计算机组成综合习题库(选择题207道&判断题93道&填空题143道)(含答案与解析)
A.输入/输出设备 B.外存储器 C.远程通信设备 D.除了CPU和内存以外的其他设备
YY的秘密代码小屋
2025/01/03
1480
【计组不挂科】计算机组成综合习题库(选择题207道&判断题93道&填空题143道)(含答案与解析)
C语言标准定义的32个关键字保姆级讲解
C语言中的数据类型主要有下面几种。实际上,数据类型可以理解为固定大小内存块的别名,给变量指定类型就是告诉编译器给该变量分配多大的内存空间,而变量相当于是内存块的门牌号。
mindtechnist
2024/08/08
1930
C语言标准定义的32个关键字保姆级讲解
Java基础知识总结(异常机制、集合、JUC、IO)
    3)、第三个是异常信息回答了为什么被抛出。Throwable是所有异常体系的顶级父类,包含了Error类和Exception类。从概念角度分析Java的异常处理机制。
别先生
2020/04/08
5510
Java基础知识总结(异常机制、集合、JUC、IO)
JAVA入门学习一
(1) JAVA 介绍 詹姆斯.高斯林(James Gosling) JAVA之父,与SUN公司的Patrick/Naughton/Mike Sheridan等人合作开发的一套语言叫”Oak”,后改名JAVA; Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言(Java面向对象程序设计语言和Java平台的总称)。
全栈工程师修炼指南
2020/10/23
3420
JAVA入门学习一
C/CPP基础知识练习题即分析
sqrt()函数在c语言中用于计算一个非负实数的平方根,开根号;其语法为double sqrt(double)。在sqrt()函数中没有sqrt (int),但是返回值可以为int,返回值可以与int类型进行运算。
CtrlX
2022/09/23
1.2K0
C/CPP基础知识练习题即分析
JAVA入门学习五
Scanner的概述:一个简单的文本扫描器,可以使用正则表达式解析原始类型和字符串,以默认空格作为分割。 Scanner的构造方法原理:
全栈工程师修炼指南
2020/10/23
5740
JAVA入门学习五
累了,代码异常!
软件开发中遇到异常才是正常,很少有人能写出完美的程序跑在任何机器上都不会报错。但极为正常的软件异常,却经常出自不同的原因,导致不同的结果。怎么样科学地认识异常、处理异常,是很多研发同学需要解决的问题。本文作者根据自己多年的工作经验,撰写了《异常思辨录》系列专栏,希望能体系化地帮助到大家。本文为系列第二篇,本篇文章将主要聚焦面向对象的分析设计和框架设计,欢迎阅读。
腾讯云开发者
2023/12/19
3771
累了,代码异常!
Java并发容器--ConcurrentHashMap
  1、不安全:大家都知道HashMap不是线程安全的,在多线程环境下,对HashMap进行put操作会导致死循环。是因为多线程会导致Entry链表形成环形数据结构,这样Entry的next节点将永远不为空,就会产生死循环获取Entry。具体内容见HashMap随笔。
在周末
2019/09/11
4720
【02】JAVASE-Java基础语法【从零开始学JAVA】
Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。
用户4919348
2024/05/25
1310
【02】JAVASE-Java基础语法【从零开始学JAVA】
Java基础
JAVA语言编译之后会生成一个.class文件,反射就是通过字节码文件找到某一个类、类中的方法以及属性等。反射机制指的是程序在运行时能够获取自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。Java
花落花相惜
2021/11/24
1.4K0
Hash算法的讲解[通俗易懂]
散列表,又叫哈希表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法。顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙。
全栈程序员站长
2022/09/20
2.3K0
Hash算法的讲解[通俗易懂]
从零开始的内存马分析——如何骑马反杀(一)
在某次实战攻防中,有一对儿小马和大马,他们两个通过了层层设备,终于打入了内网,只是在砍杀的过程中,露出了马脚,从巨大的流量中,被挖了出来,可是,真的有这么容易吗?真的如我们所愿吗?随着你的越发深入的对木马,流量进行解密,你的心中越发的不安……
亿人安全
2022/08/30
6.2K0
从零开始的内存马分析——如何骑马反杀(一)
腾讯笔试+查漏补缺 synchronized和ReentrantLock的区别
1 int main() 2 { 3 // 动态规划问题之 --- 在所给出的钱里面凑够i元最少需要多少个硬币 或 张数? 4 // 状态和状态转移方程 5 // d(
林冠宏-指尖下的幽灵
2018/01/03
1.7K0
腾讯笔试+查漏补缺
		synchronized和ReentrantLock的区别
笨办法学 Java(二)
你在上一个练习中已经看到了这一点,但你可以在if语句的主体中放入任何你喜欢的东西,包括其他if语句。这被称为“嵌套”,在另一个if语句内部的if语句称为“嵌套 if”。
ApacheCN_飞龙
2024/01/26
2220
Java基础篇Java基础语法
注释:就是对代码的解释和说明。其目的是让人们能够更加轻松地了解代码。为代码添加注释,是十分必须要的,它不影响程序的编译和运行。
程序员Leo
2023/08/07
7310
Java基础篇Java基础语法
Java 编程问题:一、字符串、数字和数学
本章包括 39 个涉及字符串、数字和数学运算的问题。我们将从研究字符串的一系列经典问题开始,例如计算重复项、反转字符串和删除空格。然后,我们将研究专门用于数字和数学运算的问题,例如两个大数求和和和运算溢出,比较两个无符号数,以及计算除法和模的下限。每个问题都要经过几个解决方案,包括 Java8 的函数风格。此外,我们将讨论与 JDK9、10、11 和 12 有关的问题。
ApacheCN_飞龙
2022/07/11
8580
以太坊智能合约OPCODE逆向之理论基础篇
在我们对etherscan等平台上合约进行安全审查时,常常会遇到没有公布Solidity源代码的合约,只能获取到合约的OPCODE,所以一个智能合约的反编译器对审计无源码的智能合约起到了非常重要的作用。
Seebug漏洞平台
2018/07/12
1.7K0
推荐阅读
相关推荐
JavaSE基础 (全网最全知识点)
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 一、入门
  • 二、初始化
  • 三、数据
    • 1. 基本类型
    • 2. 结构体
    • 3. array 和 slice
    • 4. map
    • 5. string
    • 6. set
  • 四、结构
  • 五、函数
    • 1. 返回多个值
    • 2. 闭包
    • 3. defer
    • 4. make
    • 5. append
  • 六、方法
  • 七、接口
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档