第二部分:Go语言学习笔记

发表时间: 2023-11-15 08:55

1、使用反引号包围的字符串被称为原始字符串字面量

package mainfunc main() {    println(`strings can span multiple lines with the \n escape sequence`)}// strings can span multiple lines with the \n escape sequence

2、统一码联盟把名为代码点的一系列数值赋值给上百万个独一无二的字符,Go提供了rune类型用于表示单个统一码代码点,该类型是int32的别名;还提供了uint8类型的别名byte,这种类型既可以表示二进制数据,又可以表示ASCII定义的英文字符。如果声明了一个字符变量却没有为其指定类型,那么Go将推断该变量的类型为rune;虽然rune类型代表的是一个字符,但它实际存储的仍然是数值;除此之外,字符字面量也可以搭配别名byte一同使用。

package mainimport "fmt"func main() {    var a byte = '*'    fmt.Printf("%c %[1]v\n", a) // * 42    b := '☺'    fmt.Printf("%c %[1]v\n", b) // ☺ 9786    c := 'é'    fmt.Printf("%c %[1]v", c) // é 233}

3、Go中的字符串与Java中的字符串一样,都是不可变的,不能修改。

4、Go拥有少量无须导入语句即可使用的内置函数,len函数即是其中之一,它可以测定各种不同类型的值的长度。

5、字符串使用UTF-8可变长编码,每个字符需要占用1~4个字节内存空间。utf8包的RuneCountInString函数能够以符文而不是字节为单位返回字符串的长度

package mainimport (    "fmt"    "unicode/utf8")func main() {    name := "我爱你中国"    fmt.Println(len(name), "bytes") // 15 bytes    fmt.Println(utf8.RuneCountInString(name), "runes") // 5 runes}

6、Go语言提供的关键字range不仅可以迭代各种不同的收集器,还可以解码UTF-8编码的字符串,如果不需要在迭代的时候获取索引,使用_(下划线)来省略它即可

package mainimport (    "fmt")func main() {    name := "我爱你中国"    for _, c := range name {       fmt.Printf("%v %c\n", i, c)    }}// 0 我// 3 爱// 6 你// 9 中// 12 国

7、如果想把整数类型转换为浮点型,只需要使用与新类型同名的函数来包裹该变量即可;除整数和浮点数之外,有符号数和无符号数,以及各种不同长度的类型之间都需要进行类型转换。

package mainimport "fmt"func main() {    a := 18    b := 25.6    fmt.Println(float64(a) + b) // 43.6    fmt.Println(a + int(b)) // 43}

8、通过math包提供的最小常量和最大常量,可以检测出将值转换为某种类型(如int16)是否会得到无效值。

package mainimport (    "fmt"    "math")func main() {    a := 32769    b := int16(a)    if a < math.MinInt16 || a > math.MaxInt16 {       fmt.Println("转换后会得到无效值") // 转换后会得到无效值       fmt.Println(b) // -32767    } else {       fmt.Println("可以正常转换")       fmt.Println(b)    }}

9、如下,整数与ASCII字符的相互转换

package mainimport (	"fmt"	"strconv")func main() {	a := 2	str1 := "I have " + strconv.Itoa(a) + " apples" // 整数 -> ASCII	fmt.Println(str1)	b := 3	str2 := fmt.Sprintf("I hava %v pears", b) // 整数 -> ASCII	fmt.Println(str2)	str3 := "10"	c, err := strconv.Atoi(str3) // ASCII -> 整数	if err != nil {		fmt.Println("出错了")	}	fmt.Println(c)}

10、布尔值与数值或者其他文本的互相转换,使用一个简单的if就能满足要求。

11、在Go中,以大写字母开头的函数、变量以及其他标识符都会被导出并对其他包可用,反之则不然。

12、函数声明中带有省略号...表明该函数是一个可变参数函数,它可以接受任意多个实参。

13、在同一个包中声明的函数在调用彼此时不需要加上包名作为前缀

14、声明新类型不仅能够让代码变得更加清晰,还可以有效地预防错误。

package mainimport "fmt"func main() {    type typeA float64    type typeB float64    var a typeA = 1.0    var b typeB = 2.0    fmt.Println(a + typeA(b)) // 3  	// typeA和typeB是两种不同的类型,所以它们是无法一起执行比较操作和运算的  	// 需要转换为相同的类型}

15、函数与方法

package mainimport "fmt"type celsius float64type kelvin float64func kelvinToCelsius(k kelvin) celsius {	return celsius(k - 273.15)}func (k kelvin) toCelsius() celsius {	return celsius(k - 273.15)}func main() {	var k kelvin = 294.0	var c celsius	c = kelvinToCelsius(k) // 函数调用	c = k.toCelsius() // 方法调用	fmt.Println(c)}// 函数声明中的每个形参和返回值都由名字后跟类型组成// 如果多个形参或者返回值具有相同的类型,那么类型只需要给出一次即可// 此外,函数声明中的返回值也可以省略名字,而只给出类型// 方法就像是跟特定类型相关联的函数,其中被关联的类型将通过方法名前面的接受者来指定// 方法跟函数一样,都可以接受多个形参并返回多个值,但是一个方法必须并且只能有一个接受者// 在方法内部,接受者的行为就跟其他形参一样

16、celsium、fahrenheit和kelvin3种温度类型之间互相转换的方法

package mainimport "fmt"type celsius float64type fahrenheit float64type kelvin float64func (c celsius) toFahrenheit() fahrenheit {    return fahrenheit(c*9/5 + 32)}func (c celsius) toKelvin() kelvin {    return kelvin(c + 273.15)}func (f fahrenheit) toCelsius() celsius {    return celsius((f - 32) * 5 / 9)}func (f fahrenheit) toKelvin() kelvin {    return f.toCelsius().toKelvin()}func (k kelvin) toCelsius() celsius {    return celsius(k - 273.15)}func (k kelvin) toFahrenheit() fahrenheit {    return k.toCelsius().toFahrenheit()}func main() {    c := celsius(25)    fmt.Println(c.toFahrenheit()) // 77    fmt.Println(c.toKelvin()) // 298.15    f := fahrenheit(77)    fmt.Println(f.toCelsius()) // 25    fmt.Println(f.toKelvin()) // 298.15    k := kelvin(298.15)    fmt.Println(k.toCelsius()) // 25    fmt.Println(k.toFahrenheit()) // 77}

17、在Go语言里面,函数是一等值,它可以用在整数、字符串或其他类型能够应用的所有地方:可以将函数赋给变量,可以将函数传递给函数,甚至可以编写创建并返回函数的函数

package mainimport (	"fmt"	"math/rand"	"time")type kelvin float64type sensor func() kelvin // 声明函数类型func fakeSensor() kelvin {	return kelvin(rand.Intn(151) + 150)}func realSensor() kelvin {	return 0}func measureTemperature(samples int, sensor sensor) {	for i := 0; i < samples; i++ {		k := sensor()		fmt.Printf("%v k\n", k)		time.Sleep(time.Second)	}}func main() {	sensor := fakeSensor // 将函数赋值给变量	fmt.Println(sensor())	sensor = realSensor // 将函数赋值给变量	fmt.Println(sensor())	measureTemperature(3, fakeSensor) // 将函数传递给其他函数}

18、匿名函数(在Go中也被称为函数字面量)和闭包(能够保留外部作用域的变量引用)

package mainimport "fmt"func main() {	f := func(message string) { // 匿名函数		fmt.Println(message)	}	f("Hello, World")	func(message string) { // 匿名函数		fmt.Println(message)	}("golang")}
package mainimport "fmt"type kelvin float64type sensor func() kelvinfunc realSensor() kelvin {    return 0}func calibrate(s sensor, offset kelvin) sensor {    return func() kelvin {       return s() + offset // 闭包    }}// 尽管calibrate函数已经返回了,但是被闭包捕获的变量将继续存在// 因此调用sensor仍然能够访问这两个变量func main() {    sensor := calibrate(realSensor, 5)    fmt.Println(sensor())}