day05 資料型別

凫弥發表於2024-09-17

day05 資料型別

寫程式 等價於 寫作文

資料型別,其實就是各種各樣型別的資料。

image-20200607215200860

Go語言中常見的資料型別有挺多,例如:

  • 整型,用於表示整數。
  • 浮點型,用於表示小數。
  • 布林型,用於表示真/假。
  • 字串,用於表示文字資訊。
  • 陣列,用於表示多個資料(資料集合)
  • 指標,用於表示記憶體地址的型別。
  • 切片,用於表示多個資料(資料集合)
  • 字典,用於表示鍵值對結合。
  • 結構體,用於自定義一些資料集合。
  • 介面,用於約束和泛指資料型別。

注意:關於“值型別”和“引用型別” https://github.com/go101/go101/wiki/About-the-terminology-%22reference-type%22-in-Go

今日概要

  • 整型,用於表示整數。
  • 浮點型,用於表示小數。
  • 布林型,用於表示真/假。
  • 字串,用於表示文字資訊。
  • 陣列,用於表示多個資料(資料集合)["長沙","東莞","惠州"]

1.整型

Go中的整型分為有符號和無符號兩大類,有符號的包含負值,無符號不包含負值。

有符號整型:

  • int8(-128 -> 127)
  • int16(-32768 -> 32767)
  • int32(-2,147,483,648 -> 2,147,483,647)
  • int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)
  • int
    • 在 32 位作業系統上使用 32 位(-2,147,483,648 -> 2,147,483,647) 2**32
    • 在 64 位作業系統上使用 64 位(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,80)2**64

無符號整數:

  • uint8(0 -> 255)
  • uint16(0 -> 65,535)
  • uint32(0 -> 4,294,967,295)
  • uint64(0 -> 18,446,744,073,709,551,615)
  • uint
    • 在 32 位作業系統上使用32 位(0 -> 4,294,967,295) 2**32
    • 64 位作業系統上使用 64 位(0 -> 18,446,744,073,709,551,615) 2**64

不同整型可表示的資料範圍不同,我們需要根據自己的需求來選擇適合的型別。

1.1 整型之間的轉換

data := intXXX(其他整型)
var v1 int8 = 10
var v2 int16 = 18
v3 := int16(v1) + v2
fmt.Println(v3, reflect.TypeOf(v3))

注意:

  • 地位轉向高位,沒問題。

  • 高位轉向低位,可能有問題

    var v1 int16 = 130
    v2 := int8(v1)
    fmt.Println(v2)
    

1.2 整型與字串的轉換

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

func main() {

	// 整型轉換為字串型別
	/*
		v1 := 19
		result := strconv.Itoa(v1)
		fmt.Println(result, reflect.TypeOf(result))
		var v2 int8 = 17
		data := strconv.Itoa(int(v2))
		fmt.Println(data,reflect.TypeOf(data))
	*/

	// 字串轉換為整型:轉換後是int型別;可能存在錯誤
	/*
		v1 := "666"
		result, err := strconv.Atoi(v1)
		if err == nil {
			fmt.Println("轉換成功", result,reflect.TypeOf(result))
		} else {
			fmt.Println("轉換失敗")
		}
	
	*/
}

1.3 進位制轉換

  • Go程式碼中:
    • 十進位制,整型的方式存在。
    • 其他進位制,是以字串的形式存在。
  • 整形,10進位制數。

十進位制轉換為其他進位制:

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import (
	"fmt"
	"reflect"
	"strconv"
)

func main() {
	v1 := 99
	// 整型(十進位制)轉換為:二進位制、八進位制、十六進位制
	r1 := strconv.FormatInt(int64(v1), 16)
	fmt.Println(r1, reflect.TypeOf(r1))

}

其他進位制轉換為十進位制:

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import (
	"fmt"
	"reflect"
	"strconv"
)

func main() {
	// data,要轉換的文字
	// 2,把文件當做二進位制去轉換成 十進位制(整型)
	// 16,轉換的過程中對結果進行約束
	// 結果:如果轉換成功,則將err設定為nil,result則永遠以int64的型別返回。
	data := "1001000101"
	result, err := strconv.ParseInt(data, 2, 0)
	fmt.Print(result, err, reflect.TypeOf(result))
}

提醒:透過ParseInt將字串轉換為10進位制時,本質上與Atoi是相同的。

image-20200608113745070

練習題:

  • 將十進位制 14 用 轉換成16進位制的字串。
  • 將 2進位制 "10011" 轉換成 10進位制的整型。
  • 將 2進位制 "10011" 轉換成 16 進位制的字串。

1.4 常見數學運算

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println(math.Abs(-19))                // 取絕對值
	fmt.Println(math.Floor(3.14))             // 向下取整
	fmt.Println(math.Ceil(3.14))              // 向上取整
	fmt.Println(math.Round(3.3478))           // 就近取整
	fmt.Println(math.Round(3.5478*100) / 100) // 保留小數點後兩位
	fmt.Println(math.Mod(11, 3))              // 取餘數,同11 % 3
	fmt.Println(math.Pow(2, 5))               // 計算次方,如:2的5次方
	fmt.Println(math.Pow10(2))                // 計算10次方,如:2的10次方
	fmt.Println(math.Max(1, 2))               // 兩個值,取較大值
	fmt.Println(math.Min(1, 2))               // 兩個值,取較小值
	// ...
}

1.5 指標/nil/宣告變數/new

  • 宣告變數

    var v1 int 
    v2 := 999
    

    image-20200608195751136

  • 指標

    var v3 *int    
    v4 := new(int)   
    

    image-20200608200651520

  • new關鍵字

    new用於建立記憶體並進行內部資料的初始化,並返回一個指標型別。
    
  • nil

    nil指go語言中的空值。
    var v100 *int
    var v101 *int8
    

問題:

  • 為什麼要有指標?

    為了節省記憶體,不重複開闢空間去儲存資料。
    
  • int和*int是兩種不同的資料型別,不等。(之後專門講指標細說)

1.6 超大整型

第一步:建立物件

建立超大整型物件

// 第一步:建立一個超大整型的一個物件
var v1 big.Int
var v2 big.Int

// 第二步:在超大整型物件中寫入值
v1.SetInt64(9223372036854775807)
fmt.Println(v1)

v2.SetString("92233720368547758089223372036854775808", 10)
fmt.Println(v2)
// 第一步:建立一個超大整型的一個物件
v3 := new(big.Int)
v4 := new(big.Int)

// 第二步:在超大整型物件中寫入值
v3.SetInt64(9223372036854775807)
fmt.Println(v3)

v4.SetString("92233720368547758089223372036854775808", 10)
fmt.Println(v4)

推薦:使用指標的方式,即:使用new來進行建立和初始化。

第二步:加減乘除

超大物件進行加減乘除

n1 := new(big.Int)
n1.SetInt64(89)

n2 := new(big.Int)
n2.SetInt64(99)

result := new(big.Int)
result.Add(n1, n2)

fmt.Println(result)
n1 := big.NewInt(89)

n2 := big.NewInt(99)

result := new(big.Int)
result.Add(n1, n2)

fmt.Println(result)

其他:

v1 := big.NewInt(11)
v2 := big.NewInt(3)
result := new(big.Int)

// 加
result.Add(v1, v2)
fmt.Println(result)
// 減
result.Sub(v1, v2)
fmt.Println(result)

// 乘
result.Mul(v1, v2)
fmt.Println(result)

// 除(地板除,只能得到商)
result.Div(v1, v2)
fmt.Println(result)

// 除,得商和餘數
minder := new(big.Int)
result.DivMod(v1, v2, minder)
fmt.Println(result, minder)

第三步:關於結果

n1 := new(big.Int)
n1.SetString("92233720368547758089223372036854775808", 10)

n2 := new(big.Int)
n2.SetString("11111192233720368547758089223372036854775808", 10)

result := new(big.Int)
result.Add(n1, n2)

fmt.Println(result.String())

最後建議

  • 儘量new方式去初始化並返回一個指標型別的方式。

  • 易錯的點(int型別和*int型別)

    var v1 big.Int
    v1.SetString("92233720368547758089223372036854775808", 10)
    
    var v2 big.Int
    v2.SetString("2", 10)
    
    //result := new(big.Int)
    var result big.Int
    result.Add(&v1, &v2)
    fmt.Println(result.String())
    

2.浮點型

浮點數,計算機中小數的表示方式,如:3.14

Go語言中提供了兩種浮點型:

  • float32,用32位(4個位元組)來儲存浮點型。
  • float64,用64位(8個位元組)來儲存浮點型。
/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	var v1 float32
	v1 = 3.14
	v2 := 99.9
	v3 := float64(v1) + v2
	fmt.Println(v1, v2, v3)
}

2.1 非精確

float型別,計算機中小數的非精確的表示方式,如:3.14

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	var v1 float32
	v1 = 3.14
	v2 := 99.9
	v3 := float64(v1) + v2
	fmt.Println(v1, v2, v3)

	v4 := 0.1
	v5 := 0.2
	result := v4 + v5
	fmt.Println(result)

	v6 := 0.3
	v7 := 0.2
	data := v6 + v7
	fmt.Println(data)
}
3.14 99.9 103.04000010490418
0.30000000000000004
0.5

2.2 float底層儲存原理

var price float32 = 0.29
第一步:浮點型轉換為二進位制
  • 整數部分,直接轉換為二進位制(10進位制轉換為2進位制),即:100111

  • 小數部分,讓小數部分乘以2,結果小於1則將結果繼續乘以2,結果大於1則講結果-1繼續乘以2,結果等於1則結束。

    0.29 * 2 = 0.58       // 小於1,則繼續乘
    0.58 * 2 = 1.16		  // 大於1,則減1繼續乘
    0.16 * 2 = 0.32		  // 小於1,則繼續乘
    0.32 * 2 = 0.64       // 小於1,則繼續乘
    0.64 * 2 = 1.28       // 大於1,則減1繼續乘
    0.28 * 2 = 0.56       // 小於1,則繼續乘
    0.56 * 2 = 1.12       // 大於1,則減1繼續乘
    0.12 * 2 = 0.24       // 小於1,則繼續乘    
    0.24 * 2 = 0.48       // 小於1,則繼續乘
    0.48 * 2 = 0.96       // 小於1,則繼續乘
    0.96 * 2 = 1.92       // 大於1,則減1繼續乘
    0.92 * 2 = 1.84       // 大於1,則減1繼續乘
    0.84 * 2 = 1.68       // 大於1,則減1繼續乘
    0.68 * 2 = 1.36       // 大於1,則減1繼續乘
    0.36 * 2 = 0.72       // 小於1,則繼續乘
    0.72 * 2 = 1.44       // 大於1,則減1繼續乘
    0.44 * 2 = 0.88       // 小於1,則繼續乘
    0.88 * 2 = 1.76       // 大於1,則減1繼續乘
    0.76 * 2 = 1.52       // 大於1,則減1繼續乘
    0.52 * 2 = 1.04       // 大於1,則減1繼續乘
    0.04 * 2 = 0.08       // 小於1,則繼續乘
    0.08 * 2 = 0.16       // 小於1,則繼續乘
    0.16 * 2 = 0.32       // 小於1,則繼續乘(與第三行相同,這樣會一直迴圈執行下去)
    ...
    
    將相乘之後等結果的整數部分拼接起來,所以 0.29的 二進位制表示:010010100011110101110000101000111...
    

所以,最終39.29的二進位制表示為:100111.010010100011110101110000101000111...

第二步:科學計數法表示

100111.010010100011110101110000101000111...
$$
1.00111010010100011110101110000101000111... * 2^5
$$

第三步:儲存

以float32為例來進行儲存,用32位來儲存浮點型。

image-20200608235249835

  • sign,用1位來表示浮點數正負,0表示正數;1表示負數。
  • exponent,用8位來表示共有256種(0~255),含正負值(-127 ~ 128)。例如:5想要儲存到exponent位的話,需要讓 5 + 127 = 132,再講132轉換二進位制,儲存到exponent。(132的二進位制是:01000010)
  • fraction,儲存小數點後的所有資料。

float64和float32類似,只是用於表示各部分的位數不同而已,其中:sign=1位exponent=11位fraction=52位,也就意味著可以表示的範圍更大了。

2.3 decimal

Go語言內部沒有decimal。

第三方包,則需要在本地的Go環境中先安裝再使用。第三方包原始碼地址:https://github.com/shopspring/decimal

第一步:安裝第三發的包
go get github.com/shopspring/decimal 

命令執行完成之後,在 $GOPATH/src的目錄下就會出現 github/shopspring/decimal的目錄,這就是第三方模組安排的位置。

第二步:使用decimal包
package main

import (
	"fmt"
	"github.com/shopspring/decimal"
)

func main() {

	var v1 = decimal.NewFromFloat(0.0000000000019)
	var v2 = decimal.NewFromFloat(0.29)

	var v3 = v1.Add(v2)

	var v4 = v1.Sub(v2)

	var v5 = v1.Mul(v2)

	var v6 = v1.Div(v2)
	
    fmt.Println(v3, v4, v5, v6) // 輸出:0.2900000000019(也可以呼叫String方法)
    
    
	var price = decimal.NewFromFloat(3.4626)
	var data1 = price.Round(1) 		// 保留小數點後1位(四捨五入)
	var data2 = price.Truncate(1)	// 保留小數點後1位
	fmt.Println(data1, data2) // 輸出:3.5  3.4
}

3.布林型別

表示真假,一般是和條件等配合使用,用於滿足某個條件時,執行某個操作。

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import (
	"fmt"
	"strconv"
)

func main() {
	// 字串 轉換 布林型別
	// true:"1", "t", "T", "true", "TRUE", "True"
	// false:"0", "f", "F", "false", "FALSE", "False"
	//false,err錯誤資訊
	v1, err := strconv.ParseBool("t")
	fmt.Println(v1, err)

	// 布林型別 轉換 字串
	v2 := strconv.FormatBool(false)
	fmt.Println(v2)
}

4.字串

在編寫程式時,使用字串來進行文字的處理,例如:

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	var name string = "alex"
	fmt.Printf(name)

	title := "生活要想過得去,頭上總得帶點綠"
	fmt.Printf(title)
}

4.1 字串的底層儲存

計算機中所有的操作和資料最終都是二進位制,即:1000100001011...

Go語言中的字串是utf-8編碼的序列。

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
    // unicode字符集:文字 -> 碼點(ucs4, 4個位元組表示)
    // utf-8編碼,對unicode字符集的碼點進行編碼最終得到:1000100001
	var name string = "武沛齊"
    fmt.Printf(name)
}

課上程式碼示例:

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import (
	"fmt"
	"strconv"
	"unicode/utf8"
)

func main() {
	// 1. 本質是utf-8編碼的序列
	var name string = "武沛齊"

	// 武 => 11100110 10101101 10100110
	fmt.Println(name[0], strconv.FormatInt(int64(name[0]), 2))
	fmt.Println(name[1], strconv.FormatInt(int64(name[1]), 2))
	fmt.Println(name[2], strconv.FormatInt(int64(name[2]), 2))

	// 武 => 11100110 10110010 10011011
	fmt.Println(name[3], strconv.FormatInt(int64(name[3]), 2))
	fmt.Println(name[4], strconv.FormatInt(int64(name[4]), 2))
	fmt.Println(name[5], strconv.FormatInt(int64(name[5]), 2))

	// 武 => 11101001 10111101 10010000
	fmt.Println(name[6], strconv.FormatInt(int64(name[6]), 2))
	fmt.Println(name[7], strconv.FormatInt(int64(name[7]), 2))
	fmt.Println(name[8], strconv.FormatInt(int64(name[8]), 2))

	// 2. 獲取字串的長度:9(位元組長度)
	fmt.Println(len(name))

	// 3. 字串轉換為一個"位元組集合"
	byteSet := []byte(name)
	fmt.Println(byteSet) // [230,173,166,230,178,155,233,189,144]

	// 4. 位元組的集合轉換為字串
	byteList := []byte{230, 173, 166, 230, 178, 155, 233, 189, 144}
	targetString := string(byteList)
	fmt.Println(targetString)

	// 5. 將字串轉換為 unicode字符集碼點的集合    6b66 ->  武  6c9b->沛   9f50->齊
	tempSet := []rune(name)
	fmt.Println(tempSet) // [27494 27803 40784]
	fmt.Println(tempSet[0], strconv.FormatInt(int64(tempSet[0]), 16))
	fmt.Println(tempSet[1], strconv.FormatInt(int64(tempSet[1]), 16))
	fmt.Println(tempSet[2], strconv.FormatInt(int64(tempSet[2]), 16))

	// 6. "rune集合" 轉換 為字串
	runeList := []rune{27494, 27803, 40784}
	targetName := string(runeList)
	fmt.Println(targetName)

	// 7. 長度的處理(獲取字元長度)
	runeLength := utf8.RuneCountInString(name)
	fmt.Println(runeLength)
}

4.2 字串常見功能

字串屬於在程式中最常見用的資料型別,所以Go中為字串提供了很多常見的操作。

4.2.1 獲取長度

package main

import (
   "fmt"
   "unicode/utf8"
)

func main() {
   var name string = "武沛齊"

   fmt.Println( len(name) )                    // 獲取 位元組 長度,輸出:8
   fmt.Println( utf8.RuneCountInString(name) ) // 獲取字元長度,輸出:3
}

4.2.2 是否以xx開頭

package main

import (
   "fmt"
   "strings"
)

func main() {
   name := "武沛齊"

   result := strings.HasPrefix(name, "武")

   fmt.Println(result) // 輸出:true
}

4.2.3 是否以xx結尾

package main

import (
	"fmt"
	"strings"
)

func main() {
	name := "武沛齊"

	result := strings.HasSuffix(name, "齊")

	fmt.Println(result) // 輸出:true
}

4.2.4 是否包含

package main

import (
   "fmt"
   "strings"
)

func main() {
   name := "抬老子的義大利炮來"
   result := strings.Contains(name, "老子")

   fmt.Println(result) // 輸出:true
}

4.2.5 變大寫

package main

import (
   "fmt"
   "strings"
)

func main() {
   name := "wupeiqi"

   result := strings.ToUpper(name)

   fmt.Println(result) // 輸出:WUPEIQI
}
// 注意:result是大寫;name依然是小寫。

4.2.6 變小寫

package main

import (
	"fmt"
	"strings"
)

func main() {
	name := "WUPEIQI"

	result := strings.ToLower(name)

	fmt.Println(result) // 輸出:wupeiqi
}

4.2.7 去兩邊

package main

import (
   "fmt"
   "strings"
)

func main() {
   name := "wupeiqi"

   result1 := strings.TrimRight(name, "qi") // 去除右邊的qi
   result2 := strings.TrimLeft(name, "w")   // 去除左邊的w
   result3 := strings.Trim(name, "w")       // 去除兩邊的w

   fmt.Println(result1, result2, result3) // 輸出:wupe upeiqi upeiqi
}

4.2.8 替換

package main

import (
   "fmt"
   "strings"
)

func main() {
   name := "wupeipeiqi"

   result1 := strings.Replace(name, "pei", "PE", 1)  // 找到pei替換為PE,從左到右找第一個替換
   result2 := strings.Replace(name, "pei", "PE", 2)  // 找到pei替換為PE,從左到右找前兩個替換
   result3 := strings.Replace(name, "pei", "PE", -1) // 找到pei替換為PE,替換所有

   fmt.Println(result1, result2, result3)
}

4.2.9 分割

package main

import (
   "fmt"
   "strings"
)

func main() {
   name := "抬老子的義大利的炮來"
   result := strings.Split(name, "的")

   // 根據`的`進行切割,獲取一個切片(類似於一個陣列)
   fmt.Println(result) // [ 抬老子, 義大利, 炮來 ]
}

4.2.10 拼接

可以使用 + 讓兩個字串進行拼接,但這樣的拼接效率會非常的低,不建議使用,建議大家使用以下的方式:

package main

import (
	"bytes"
	"fmt"
	"strings"
)

func main() {
	// 不建議
	message := "我愛" + "北京天安門"
	fmt.Println(message)

	// 建議:效率高一些
	dataList := []string{"我愛", "北京天安門"}
	result := strings.Join(dataList, "")
	fmt.Println(result) // 我愛北京天安門

	// 建議:效率更高一些(go 1.10之前)
	var buffer bytes.Buffer
	buffer.WriteString("你想")
	buffer.WriteString("我幹")
	buffer.WriteString("他")
	data := buffer.String()
	fmt.Print(data)

	// 建議:效率更更更更高一些(go 1.10之後)
	var builder strings.Builder
	builder.WriteString("哈哈哈")
	builder.WriteString("去你的吧")
	value := builder.String()
	fmt.Print(value)
}

4.2.11 string轉換為int

package main

import (
	"fmt"
	"strconv"
)

func main() {
	num := "666"

	// 內部呼叫的就是 ParseInt
	var data, _ = strconv.Atoi(num)
	fmt.Println(data)
    
    // 整型轉字串(strconv.ParseInt 和 strconv.FormatInt 可用處理進位制轉換)
    // 十進位制:整型; 其他進位制:字串形式 
    var result, err = strconv.ParseInt(num, 10, 32)
	fmt.Println(result, err)
}

4.2.12 int轉換為string

package main

import (
	"fmt"
	"strconv"
)

func main() {
	var result = strconv.Itoa(888)
	fmt.Println(result)
}

4.2.13 字串 和 “位元組集合”

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import (
	"fmt"
	"strconv"
	"unicode/utf8"
)

func main() {

	var name string = "武沛齊"

	// 字串轉換為一個"位元組集合"
	byteSet := []byte(name)
	fmt.Println(byteSet) // [230,173,166,230,178,155,233,189,144]

	// 位元組的集合轉換為字串
	byteList := []byte{230, 173, 166, 230, 178, 155, 233, 189, 144}
	targetString := string(byteList)
	fmt.Println(targetString)

}

4.2.14 字串 和 “rune集合”

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import (
	"fmt"
	"strconv"
	"unicode/utf8"
)

func main() {

	var name string = "武沛齊"

	// 將字串轉換為 unicode字符集碼點的集合    6b66 ->  武  6c9b->沛   9f50->齊
	tempSet := []rune(name)
	fmt.Println(tempSet) // [27494 27803 40784]
	fmt.Println(tempSet[0], strconv.FormatInt(int64(tempSet[0]), 16))
	fmt.Println(tempSet[1], strconv.FormatInt(int64(tempSet[1]), 16))
	fmt.Println(tempSet[2], strconv.FormatInt(int64(tempSet[2]), 16))

	// "rune集合" 轉換 為字串
	runeList := []rune{27494, 27803, 40784}
	targetName := string(runeList)
	fmt.Println(targetName)
}

4.2.15 string 和 字元

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	// 數字轉字串
	v1 := string(65)
	fmt.Println(v1) // A
    
    v2 := string(27494)
	fmt.Println(v2) // 武
    
	// 字串轉數字
	v3, size := utf8.DecodeRuneInString("A")
	fmt.Println(v3, size) // 65    1
    
    v4, size := utf8.DecodeRuneInString("武")
	fmt.Println(v4, size) // 27494 3

}

應用場景:生成一個隨機數,然後呼叫string得到一個隨機的字元。

4.3 索引切片和迴圈

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	var name string = "武沛齊"

	// 1. 索引獲取位元組
	v1 := name[0]
	fmt.Println(v1)  // 230

	// 2. 切片獲取位元組區間
	v2 := name[0:3]
	fmt.Println(v2)  // 武

	// 3. 手動迴圈獲取所有位元組
    /*
        0 230
        1 173
        2 166
        3 230
        4 178
        5 155
        6 233
        7 189
        8 144
    */
	for i := 0; i < len(name); i++ {
		fmt.Println(i, name[i]) 
	}

	// 4. for range 迴圈獲取所有字元
    /*
        0 27494 武
        3 27803 沛
        6 40784 齊
	*/
	for index, item := range name {
        fmt.Println(index, item, string(item))
	}

	// 5.轉換成rune集合 [27494,27803,40784]
	dataList := []rune(name)
	fmt.Println(dataList[0], string(dataList[0]))

}

5.陣列

陣列,定長且元素型別一致的資料集合。

// 方式一:先宣告再賦值(宣告時記憶體中已開闢空間,記憶體初始化的值是0)
var numbers [3]int
numbers[0] = 999
numbers[1] = 666
numbers[2] = 333

// 方式二:宣告+賦值
var names = [2]string{"武沛齊","alex"}

// 方式三:宣告+賦值 + 指定位置
var ages = [3]int{0:87,1:73,2:99}

// 方式四:省略個數
var names = [...]string{"武沛齊","alex"}
var ages = [...]int{  0:87,  2:99 }
// 宣告 指標型別的陣列(指標型別),不會開闢記憶體初始化陣列中的值,numbers = nil
var numbers *[3]int

// 宣告陣列並初始化,返回的是 指標型別的陣列(指標型別)
numbers := new([3]int)

5.1 陣列記憶體管理

image-20200610112239589

陣列,定長且元素型別一致的資料集合。

必備知識點:

  • 陣列的記憶體是連續的。

  • 陣列的記憶體地址實際上就是陣列第一個元素的記憶體地址。

  • 每個字串的內部儲存:len + str

    type stringStruct struct {
    	str unsafe.Pointer
    	len int
    }
    

示例1:

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	nums := [3]int8{11, 22, 33}

	fmt.Printf("陣列的記憶體地址:%p \n", &nums)
	fmt.Printf("陣列第1個元素的記憶體地址:%p \n", &nums[0])
	fmt.Printf("陣列第2個元素的記憶體地址:%p \n", &nums[1])
	fmt.Printf("陣列第3個元素的記憶體地址:%p \n", &nums[2])
}

>>> 輸出
陣列的記憶體地址:0xc00001604a 
陣列第1個元素的記憶體地址:0xc00001604a 
陣列第2個元素的記憶體地址:0xc00001604b 
陣列第3個元素的記憶體地址:0xc00001604c 

示例2:

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	nums := [3]int32{11, 22, 33}

	fmt.Printf("陣列的記憶體地址:%p \n", &nums)
	fmt.Printf("陣列第1個元素的記憶體地址:%p \n", &nums[0])
	fmt.Printf("陣列第2個元素的記憶體地址:%p \n", &nums[1])
	fmt.Printf("陣列第3個元素的記憶體地址:%p \n", &nums[2])
}

>>> 輸出
陣列的記憶體地址:0xc0000b4004 
陣列第1個元素的記憶體地址:0xc0000b4004 
陣列第2個元素的記憶體地址:0xc0000b4008 
陣列第3個元素的記憶體地址:0xc0000b400c 

示例3:

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	names := [2]string{"武沛齊", "alex"}
	fmt.Printf("陣列的記憶體地址:%p \n", &names)
	fmt.Printf("陣列第1個元素的記憶體地址:%p \n", &names[0])
	fmt.Printf("陣列第2個元素的記憶體地址:%p \n", &names[1])

}

>>> 輸出:
陣列的記憶體地址:0xc000128020 
陣列第1個元素的記憶體地址:0xc000128020 
陣列第2個元素的記憶體地址:0xc000128030

5.2 可變和複製

可變,陣列的元素可以被更改(長度和型別都不可以修改)。

names := [2]string{"武沛齊", "alex"}
names[1] = "苑昊"

注意:字串不可以被修改。 "武沛齊" "武陪齊"

複製,變數賦值時重新複製一份。

name1 := [2]string{"武沛齊", "alex"}
name2 := name1

name1[1] = "苑昊"

fmt.Println(name1,name2)   // [武沛齊 苑昊]   [武沛齊 alex]

5.3 長度索引切片和迴圈

/*
 @Author:武沛齊  微訊號:wupeiqi666
 @Description: 老男孩IT教育 & 路飛學城
 @Video:  https://space.bilibili.com/283478842
*/
package main

import "fmt"

func main() {
	// 1. 長度
	//name := [2]string{"武沛齊", "alex"}
	//fmt.Println(len(name))

	// 2. 索引
	//name := [2]string{"武沛齊", "alex"}
	//data := name[0]
	//fmt.Println(data)
	//name[0] = "eric"
	//fmt.Println(name)

	// 3. 切片
	//nums := [3]int32{11, 22, 33}
	//data := nums[0:2] // 獲取   0 <= 下標 < 2
	//fmt.Println(data)

	// 4. 迴圈
	//nums := [3]int32{11, 22, 33}
	//for i:=0;i<len(nums);i++{
	//	fmt.Println(i, nums[i] )
	//}

	// 5.for range 迴圈
	nums := [3]int32{11, 22, 33}
	for key, item := range nums {
		fmt.Println(key, item)
	}

	for key := range nums {
		fmt.Println(key)
	}

	for _,item := range nums {
		fmt.Println(item)
	}

}

5.4 陣列巢狀

// [0,0,0]
//var nestData [3]int

// [ [  [0,0,0],[0,0,0]  ],[  [0,0,0],[0,0,0]  ],[  [0,0,0],[0,0,0]  ], ]
//var nestData [3][2][3]int

// [  [0,0,0],[0,0,0]  ]
//var nestData [2][3]int
//nestData[0] = [3]int{11, 22, 33}
//nestData[1][1] = 666
//fmt.Println(nestData)

//nestData := [2][3]int{[3]int{11, 22, 33}, [3]int{44, 55, 66}}
//fmt.Println(nestData)

作業題(21道)

  1. Go語言中int佔多少位元組?

  2. 整型中有符號和無符號是什麼意思?

  3. 整型可以表示的最大範圍是多少?超出怎麼辦?

  4. 什麼是nil?

  5. 十進位制是以整型方式存在,其他進位制則是以字串的形式存在?如何實現進位制之間的轉換?

  6. 簡述如下程式碼的意義

    var v1 int
    var v2 *int
    var v3 = new(int)
    
  7. 浮點型為什麼有時無法精確表示小數?

  8. 如何使用第三方包 decimal?

  9. 簡述 ascii、unicode、utf-8的關係。

  10. 判斷:Go語言中的字串是utf-8編碼的位元組序列。

  11. 什麼是rune?

  12. 判斷:字串是否可變?

  13. 列舉你記得的字串的常見功能?

  14. 字串和 “位元組集合” 、“rune集合” 如何實現相互轉換?

  15. 字串如何實現高效的拼接?

  16. 簡述陣列的儲存原理。

  17. 根據要求寫程式碼

    names := [3]string{"Alex","超級無敵小jj","傻兒子"}
    
    a. 請根據索引獲取“傻兒子”
    b. 請根據索引獲取“alex”
    c. 請根據索引獲取“小jj”
    d. 請將name陣列的最後一個元素修改為 “大燒餅”
    
  18. 看程式碼寫輸出結果

    var nestData [3][2]int
    fmt.Println(nestData)
    
  19. 請宣告一個有3個元素的陣列,元素的型別是有兩個元素的陣列,並在陣列中初始化值。例如:

    [ 
        ["alex","qwe123"],
        ["eric","admin11"],
        ["tony","pp1111"] 
    ]
    
  20. 迴圈如下陣列並使用字串格式化輸出如下內容:

    dataList := [ 
        ["alex","qwe123"],
        ["eric","admin11"],
        ["tony","pp1111"] 
    ]
    
    請補充程式碼...
    
    
    最終實現輸出:
    我是alex,我的密碼是qwe123。
    我是eric,我的密碼是admin11。
    我是tony,我的密碼是pp1111。
    
  21. 補充程式碼實現使用者登入

    // userList表示有三個使用者,每個使用者有使用者名稱和密碼,例如:使用者名稱是alex,密碼是qwe213
    userList :=  [ 
        ["alex","qwe123"],
        ["eric","admin11"],
        ["tony","pp1111"] 
    ]
    
    // 需求:提示讓使用者輸入使用者名稱和密碼,然後再userList中校驗使用者名稱和密碼是否正確。
    

相關文章