Golang 笔记 1

一、Go语言基础

1. 基础

Go语言中的标识符必须以字母(Unicode字母,PHP/JS可以用中文作为变量名)下划线开头。大写字母跟小写字母是不同的:Hello和hello是两个不同的名字。
  Go中有25个关键字:

break    default     func   interface select
case     defer       go     map       struct
chan     else        goto   package   switch
const    fallthrough if     range     type
continue for         import return    var

如果一个名字是在函数内容定义,那么它的作用域就在函数内容,如果在函数外部定义,那么将在当前包的所有文件中都可以访问。名字的开头字母的大小写决定了名字在包外的可见性。如果一个名字是大写字母开头,那么它可以被外部的包访问,例如fmt包的Printf函数。

2. 注释

  • 单行注释 // ...
  • 多行注释 /* ... */

3. Go程序的一般结构

  • Go程序是通过package来组织的
  • 只有package名称为main的包可以包含main函数
  • 一个可执行程序有且只有一个main包
// 当前程序的包名
package main
// 导入其他的包
import "fmt"
// 一次导入多个包
import (
    "io"
    "os"
)
// 常量的定义
const PI = 3.14
// 全局变量的声明与赋值,该变量在整个package中使用
var name = "go"
// 一般类型声明
type newType int
// 结构的声明
type go struct{}
// 接口的声明
type golang interface{}
// 由main函数作为程序入口启动
func main() {
    fmt.Println("Hello World!")
}
  • 如果导入的包但是没有用到类型或者函数则会报编译错误
  • package别名: import io "fmt" 这样将fmt设置一个别名为io,调用的时候就可以这样: io.Println("...")

4. 可见性规则

Go语言中使用大小写来决定该常量、变量、类型、接口、结构或函数是否可以被外部包所调用: 根据约定,函数名首字母小写即为private(外部不可以调用),大写为public

二、基本数据类型

1、变量和常量

  • 普通赋值:
// var 变量名称 变量类型 = 值
var num int = 1
  • 平行赋值
var num1,num2 int = 1, 2
  • 多行赋值
var (
    num1 int = 1
    num2 int = 2
)

2、整数类型的命名和宽度

Go的整数类型一共有10个
  其中计算架构相关的整数类型有两个: 有符号的整数类型 int, 无符号的整数类型 uint。
  在不同计算架构的计算机上,它们体现的宽度(存储某个类型的值所需要的空间)是不一样的。空间的单位可以是bit也可以是字节byte。
  

除了这两个计算架构相关的整数类型之外,还有8个可以显式表达自身宽度的整数类型:
  

3、整数类型值的表示法

如果以8进制为变量num赋值:

num = 039 // 用"0"作为前缀以表明这是8进制表示法

如果以16进制为变量num赋值:

num = 0x39

4、浮点数类型

浮点数类型有两个:float32/float64   浮点数类型的值一般由整数部分、小数点"."和小数部分组成。另外一种表示方法是在其中加入指数部分。指数部分由"E"或"e"以及带正负号的10进制整数表示。例:3.9E-2表示浮点数0.039。3.9E+1表示浮点数39。
  有时候浮点数类型值也可以被简化。比如39.0可以被简化为39。0.039可以被简化为.039。   在Go中浮点数的相关部分只能由10进制表示法表示。

5、复数类型

复数类型有两个:complex64和complex128。实际上,complex64类型的值会由两个float32类型的值分别表示复数的实数部分和虚数部分。而complex128类型的值会由两个float64类型的值表示复数的实数部分和虚数部分。
  负数类型的值一般由浮点数表示的实数部分、加号"+"、浮点数表示的虚数部分以及小写字母"i"组成,比如3.9E+1 + 9.99E-2i。

6、byte与rune

byte与rune都属于别名类型。byte是uint8的别名类型,而rune是int32的别名类型。
  一个rune的类型值即可表示一个Unicode字符。一个Unicode代码点通常由"U+"和一个以十六进制表示法表示的整数表示,例如英文字母‘A‘的Unicode代码点为"U+0041"。
  rune类型的值需要由单引号"‘"包裹,不过我们还可以用另外几种方式表示: [待截图]
  另外在rune类型值的表示中支持几种特殊的字符序列,即:转义符。如下图: [待截图]

7、字符串类型

字符串的表示法有两种,即:原生表示法和解释型表示法。原生表示法,需用用反引号"`"把字符序列包起来,如果用解释型表示法,则需要用双引号"""包裹字符序列。

var str1 string = "str"
var str1 string = `str`

二者的区别是,前者表示的是所见即所得的(除了回车符)。后者所表示的值中转义符会起作用。字符串值是不可变的,如果我们创建了一个此类型的值,就不可能再对它本身做任何修改。

三、高级数据类型

1、数组类型

一个数组是可以容纳若干相同类型的元素的容器。数组的长度是固定的。如下声明一个数组类型:

type MyNumbers [3]int

类型声明语句由关键字type、类型名称和类型字面量组成

上面这条类型声明语句实际上是为数组类型[3]int声明了一个别名类型。这使得我们可以把MyNumbers当作数组类型[3]int来使用。
  我们表示这样一个数组类型的值的时候。应该把该类型的类型字面量写在最左边,然后用花括号包裹该值包含的若干元素,各元素之间以(英文半角)逗号分割,即:

[3]int{1,2,3}

现在我们把这个数组字面量赋给一个名为numbers的变量:

var numbers = [3]int{1,2,3}

这是一条变量声明语句,它在声明变量的同时为该变量赋值

另一种方式是在其中的类型字面量中省略代表其长度的数组,例:

var numbers = [...]int{1,2,3}

可以用如下方式访问该变量中的任何一个元素。例:

numbers[0]
numbers[1]
numbers[2]

如果要修改数组值中的某一个元素值,可以:

numbers[1] = 4

可以用如下方式获取数组长度:

var length = len(numbers)

如果一个数组没有赋值,则它的默认值为[length]type{0,0,0...}

2、切片类型

(1) 基础

切片(slice)与数组一样也是可以若干相同类型元素的容器。与数组不同的是切片类型的长度不确定。每个切片值都会将数组作为其底层数据结构。表示切片类型的字面量如:

[]int

或者是:

[]string

切片类型的声明可以这样:

type MySlice []int

对切片值的表示也与数组值相似

[]int{1,2,3}

操作数组值的方法同样适用于切片值。还有一种操作数组的方式叫做“切片”,实施切片操作的方式就是切片表达式。例:

var number3 = [5]int{1,2,3,4,5}
var slice1 = numbers3[1:4]

上例中切片表达式numbers3[1:4]的结果为[]int{2,3,4}很明显被切下的部分不包含元素上界索引指向的元素。实际上slice1这个切片值的底层数组正是number3的值。
  我们也可以在切片值上实施切片操作:

var slice2 = slice1[1:3]

除了长度切片值以及数组值还有另外一个属性--容量。数组的容量总是等于其长度,而切片值的容量往往与其长度不同。如下图: [待截图]
  如图所示,一个切片值的容量即为它的第一个元素值在其底层数组中的索引值与该数组长度的差值的绝对值。可以使用cap()内建函数获取数组、切片、通道类型的值的容量:

var capacity2 int = cap(slice2)

切片类型属于引用类型,它的零值即为nil,即空值。如果我们只声明了一个切片类型而不为它赋值,则它的默认值:nil。

(2) 切片的更多操作方法

有些时候我们可以在方括号中放入第三个正整数。如下图所示:

numbers3[1:4:4]

第三个正整数为容量上界索引,它意义在于可以把作为结果的切片值的容量设置的更小。它可以限制我们通过这个切片值对其底层数组中的更多元素的访问。上节中numbers3和slice的赋值语句如下:

var numbers3 = [5]int{1,2,3,4,5}
var slice1 = numbers3[1:4]

这时,变量slice1的值是[]int{2,3,4}。但是我们可以通过如下操作将其长度延展与其容量相同:

slice1 = slice1[:cap(slice1)]

通过此操作,变量slice1的值变为了[]int{2,3,4,5},且其长度和容量均为4。现在number3的值中的索引值在(1,5)范围内的元素都被体现在了slice1的值中。这是以number3的值是slice1的值的底层数组为前提的。这意味着我们可以轻而易举地通过切片访问其底层数组中对应索引值更大的更多元素。如果我们编写的函数返回了这样一个切片值,那么得到它的程序很可能会通过这种技巧访问到本不应该暴露给它的元素。
  如果我们在切片中加入了第三个索引(即容量上限索引),如:

var slice1 = numbers3[1:4:4]

那么在此之后,我们将无法通过slice1访问到number3的值中的第五个元素。
  虽然切片值在上述方面受到了其容量的限制。但是我们可以通过另外一种手段对其进行不受限制的扩展。这需要用到内建函数append。append会对切片值进行扩展并返回一个新的切片值,使用方法如下:

slice1 = append(slice1, 6, 7)

通过上述操作,slice1的值变为了[]int{2,3,4,6,7}。一旦扩展操作超出了被操作的切片值的容量,那么该切片的底层数组就会被替换   最后一种操作切片的方式是“复制”。该操作的实施方法是调用copy函数。该函数接收两个类型相同的切片值作为参数,并把第二个参数值中的元素复制到第一个参数值中的相应位置(索引值相同)上。这里有两点需要注意:

  1. 这种复制遵循最小复制原则,即:被复制的元素的个数总是等于长度较短的那个参值的长度。
  2. 与append函数不同,copy函数会直接对其第一个参数值进行修改。

例:

var slice4 = []int{0,0,0,0,0,0}
copy(slice4, slice1)

通过上述复制操作,slice4会变成[]int{2,3,4,6,7,0,0}。

时间: 2024-10-08 08:13:44

Golang 笔记 1的相关文章

【GoLang笔记】实例分析GoLang built-in数据结构map的赋值引用行为

备注1:本文旨在介绍Go语言中map这个内置数据结构的引用行为,并用实例来说明如何避免这种引用行为带来的"副作用". 备注2:文末列出的参考资料均来自GoLang.org官方文档,需翻墙访问. 1. map internals map是go中内置的数据结构,关于其语法规则,可以查看language specification中这里的说明,或者查看Effective Go中关于Maps的说明,此处略过. map的底层是用hashmap实现的(底层hashmap源码路径为src/pkg/r

【GoLang笔记】遍历map时的key随机化问题及解决方法

之前的一篇笔记曾分析过,Go的map在底层是用hashmap实现的.由于高效的hash函数肯定不是对key做顺序散列的,所以,与其它语言实现的hashmap类似,在使用Go语言map过程中,key-value的插入顺序与遍历map时key的访问顺序是不相同的.熟悉hashmap的同学对这个情况应该非常清楚. 所以,本文要提到的肯定不是这个,而是一个比较让人惊奇的情况,下面开始说明. 1. 通过range遍历map时,key的顺序被随机化 在golang 1.4版本中,借助关键字range对Go语

golang笔记——环境搭建

1.下载安装 从 https://golang.org/dl/ 这里下载最新版本的 golang 安装包,分别有 Windows\Linux\Apple OSX\源码包. golang的官方网站是 https://golang.org/ ,对应的中文版网站是 https://go-zh.org/ ,对中国开发者还是很友好啊. 2.环境配置 go 语言相比其它语言,初次安装配置要麻烦一点,需要手动配置环境变量 GOROOT,值为 go 的安装路径,以 Windows 安装为例,我这里为 c:/go

golang笔记:unsupported driver -> Scan pair: <nil> -> *string

golang里,操作mysql数据库,使用查询语句的时候,一般的写法 rows, err := db.Query("SELECT name from table) if err != nil { return } for rows.Next() { var name string err = rows.Scan(&name) if err != nil { return } } 当查出来的字段有NULL的时候,就会报这样的错误unsupported driver -> Scan p

GoLang笔记-数组和切片,本质是就是长度不可变的可变的区别

数组 Arrays 数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值.在初始化后长度是固定的,无法修改其长度.当作为方法的入参传入时将复制一份数组而不是引用同一指针.数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度. 初始化 数组的初始化有多种形式,查看示例代码 , 在线运行示例代码 [5] int {1,2,3,4,5} 长度为5的数组,其元素值依次为:1,2,3,4,5 [5] int {1,2} 长度为5的数组

golang笔记——命令

1.GO命令一览 GO提供了很多命令,包括打包.格式化代码.文档生成.下载第三方包等等诸多功能,我们可以通过在控制台下执行 go 来查看内置的所有命令 下面来逐个介绍,也可以详细参考 https://github.com/hyper-carrot/go_command_tutorial 2.go build

golang笔记——包

1.包简述 GO本身没有项目的概念,只有包,包括可执行包和不可执行包,而不管什么包,都应该包含在 $GOPATH/src 目录下,GO命令和编译器会在 $GOPATH/src 目录下搜索相应的包.比如 import "logging" 则会在所有设置的 $GOPATH/src 下去寻找相应包,而不仅仅是当前项目中. 2.包声明 在每一个代码文件中,都需要使用 package 命令来声明包名,所以在GO语言中,代码文件属于哪个包与文件目录结构没有必然联系,但习惯上我们会设置成跟目录结构相

golang笔记——string

任何语言中,字符串操作API都是非常重要的,有些还是熟记比较好,当然如果记不住可以去看源码文件,不得不说GO语言源码看起来非常舒服. 字符串操作相关的API大多封装在 strings 包里,下面列一些常见的 func Count(s, sep string) int 获取指定子字符串的个数 func Contains(s, substr string) bool 判断是否包括某子字符串 func ContainsAny(s, chars string) bool 判断是否包括某字符串中的做任意一

golang笔记(1)-数据库查询结果映射至结构体

通用的映射模式 query:="select id,name from user where id=?" //单个结构体ret:=&Activity{} DbClient().Find(query,activityId).Unique(ret)//结构体数组ret:=[]Activity{} DbClient().Find(query,activityId).List(&ret)   1.定义结构体 type Activity struct{ ID int64 `col