隨著金融科技的發展,越來越多的人選擇線上銀行或移動銀行上進行日常交易。在進行這些交易之前,通常需要進行身份驗證以確保賬戶的安全性。其中,銀行卡二要素驗證是一種常見的身份驗證方式。本文將為大家介紹如何使用銀行卡二要素驗證API介面,具體實現方法如下。 一、API介面介紹 銀行卡二要素驗證API介面是一 ...
九、錯誤處理
1.defer+recover機制處理異常錯誤
展示錯誤:
發現:程式中出現錯誤/恐慌以後,程式被中斷,無法繼續執行。
錯誤處理/捕獲機制:
內置函數recover:
2.自定義錯誤
需要調用errors包下的New函數:函數返回error類型
3.panic
有一種情況:程式出現錯誤以後,後續代碼就沒有必要執行,想讓程式中斷,退出程式:
藉助:builtin包下內置函數:panic
十、數組
1.使用
數組定義格式:
var 數組名 [數組大小]數據類型
例如:
var scores [5]int
package main
import "fmt"
func main(){
//實現的功能:給出五個學生的成績,求出成績的總和,平均數:
//給出五個學生的成績:--->數組存儲:
//定義一個數組:
var scores [5]int
//將成績存入數組:
scores[0] = 95
scores[1] = 91
scores[2] = 39
scores[3] = 60
scores[4] = 21
//求和:
//定義一個變數專門接收成績的和:
sum := 0
for i := 0;i < len(scores);i++ {//i: 0,1,2,3,4
sum += scores[i]
}
//平均數:
avg := sum / len(scores)
//輸出
fmt.Printf("成績的總和為:%v,成績的平均數為:%v",sum,avg)
}
2.記憶體分析
賦值記憶體(數組是值類型,在棧中開闢記憶體)
3.數組的遍歷
【1】普通for迴圈
【2】鍵值迴圈
(鍵值迴圈) for range結構是Go語言特有的一種的迭代結構,在許多情況下都非常有用,for range 可以遍曆數組、切片、字元串、map 及通道,for range 語法上類似於其它語言中的 foreach 語句,一般形式為:
for key, val := range coll {
...
}
註意:
(1)coll就是你要的數組
(2)每次遍歷得到的索引用key接收,每次遍歷得到的索引位置上的值用val
(3)key、value的名字隨便起名 k、v key、value
(4)key、value屬於在這個迴圈中的局部變數
(5)你想忽略某個值:用_就可以了:
package main
import "fmt"
func main(){
//實現的功能:給出五個學生的成績,求出成績的總和,平均數:
//給出五個學生的成績:--->數組存儲:
//定義一個數組:
var scores [5]int
//將成績存入數組:(迴圈 + 終端輸入)
for i := 0; i < len(scores);i++ {//i:數組的下標
fmt.Printf("請錄入第個%d學生的成績",i + 1)
fmt.Scanln(&scores[i])
}
//展示一下班級的每個學生的成績:(數組進行遍歷)
//方式1:普通for迴圈:
for i := 0; i < len(scores);i++ {
fmt.Printf("第%d個學生的成績為:%d\n",i+1,scores[i])
}
fmt.Println("-------------------------------")
//方式2:for-range迴圈
for key,value := range scores {
fmt.Printf("第%d個學生的成績為:%d\n",key + 1,value)
}
}
結果:
4.數組的初始化操作
package main
import "fmt"
func main(){
//第一種:
var arr1 [3]int = [3]int{3,6,9}
fmt.Println(arr1)
//第二種:
var arr2 = [3]int{1,4,7}
fmt.Println(arr2)
//第三種:
var arr3 = [...]int{4,5,6,7}
fmt.Println(arr3)
//第四種:
var arr4 = [...]int{2:66,0:33,1:99,3:88}
fmt.Println(arr4)
}
5.註意事項
【1】長度屬於類型的一部分 :
【2】Go中數組屬值類型,在預設情況下是值傳遞,因此會進行值拷貝。
【3】如想在其它函數中,去修改原來的數組,可以使用引用傳遞(指針方式)。
6.二維數組
二維數組有初始值,
初始化:
遍歷
package main
import "fmt"
func main(){
//定義二維數組:
var arr [3][3]int = [3][3]int{{1,4,7},{2,5,8},{3,6,9}}
fmt.Println(arr)
fmt.Println("------------------------")
//方式1:普通for迴圈:
for i := 0;i < len(arr);i++{
for j := 0;j < len(arr[i]);j++ {
fmt.Print(arr[i][j],"\t")
}
fmt.Println()
}
fmt.Println("------------------------")
//方式2:for range迴圈:
for key,value := range arr {
for k,v := range value {
fmt.Printf("arr[%v][%v]=%v\t",key,k,v)
}
fmt.Println()
}
}
十一、切片
【1】切片(slice)是golang中一種特有的數據類型
【2】數組有特定的用處,但是卻有一些呆板(數組長度固定不可變),所以在 Go 語言的代碼里並不是特別常見。相對的切片卻是隨處可見的,切片是一種建立在數組類型之上的抽象,它構建在數組之上並且提供更強大的能力和便捷。
【3】切片(slice)是對數組一個連續片段的引用,所以切片是一個引用類型。這個片段可以是整個數組,或者是由起始和終止索引標識的一些項的子集。需要註意的是,終止索引標識的項不包括在切片內。切片提供了一個相關數組的動態視窗。
1.語法
var 切片名 []類型 = 數組的一個片段引用
2.記憶體分析
切片有3個欄位的數據結構:一個是指向底層數組的指針,一個是切片的長度,一個是切片的容量。
3.定義
【1】方式1:定義一個切片,然後讓切片去引用一個已經創建好的數組。
【2】方式2:通過make內置函數來創建切片。基本語法: var切片名[type = make([], len,[cap])
make底層創建一個數組,對外不可見,所以不可以直接操作這個數組,要通過slice去間接的訪問各個元素,不可以直接對數組進行維護/操作
【3】方式3:定一個切片,直接就指定具體數組,使用原理類似make的方式。
4.遍歷
【1】方式1:for迴圈常規方式遍歷
【2】方式2:for-range 結構遍歷切片
package main
import "fmt"
func main(){
//定義切片:
slice := make([]int,4,20)
slice[0] = 66
slice[1] = 88
slice[2] = 99
slice[3] = 100
//方式1:普通for迴圈
for i := 0;i < len(slice);i++ {
fmt.Printf("slice[%v] = %v \t" ,i,slice[i])
}
fmt.Println("\n------------------------------")
//方式2:for-range迴圈:
for i,v := range slice {
fmt.Printf("下標:%v ,元素:%v\n" ,i,v)
}
}
5.註意事項
【1】切片定義後不可以直接使用,需要讓其引用到一個數組,或者make一個空間供切片來使用
【2】切片使用不能越界。
【3】簡寫方式:
- var slice = arr[0:end] ----》 var slice = arr[:end]
- var slice = arr[start:len(arr)] ----》 var slice = arr[start:]
- var slice = arr[0:len(arr)] ----》 var slice = arr[:]
【4】切片可以繼續切片
【5】切片可以動態增長
package main
import "fmt"
func main(){
//定義數組:
var intarr [6]int = [6]int{1,4,7,3,6,9}
//定義切片:
var slice []int = intarr[1:4] //4,7,3
fmt.Println(len(slice))
slice2 := append(slice,88,50)
fmt.Println(slice2) //[4 7 3 88 50]
fmt.Println(slice)
//底層原理:
//1.底層追加元素的時候對數組進行擴容,老數組擴容為新數組:
//2.創建一個新數組,將老數組中的4,7,3複製到新數組中,在新數組中追加88,50
//3.slice2 底層數組的指向 指向的是新數組
//4.往往我們在使用追加的時候其實想要做的效果給slice追加:
slice = append(slice,88,50)
fmt.Println(slice)
//5.底層的新數組 不能直接維護,需要通過切片間接維護操作。
}
可以通過append函數將切片追加給切片:
【6】切片的拷貝:
package main
import "fmt"
func main(){
//定義切片:
var a []int = []int{1,4,7,3,6,9}
//再定義一個切片:
var b []int = make([]int,10)
//拷貝:
copy(b,a) //將a中對應數組中元素內容複製到b中對應的數組中
fmt.Println(b)
}
十二、映射
1.map的引入
【1】映射(map), Go語言中內置的一種類型,它將鍵值對相關聯,我們可以通過鍵 key來獲取對應的值 value。 類似其它語言的集合
【2】基本語法
var map變數名 map[keytype]valuetype
key、value的類型:bool、數字、string、指針、channel 、還可以是只包含前面幾個類型的介面、結構體、數組
key通常為int 、string類型,value通常為數字(整數、浮點數)、string、map、結構體
key:slice、map、function不可以
【3】代碼:
map的特點:
(1)map集合在使用前一定要make
(2)map的key-value是無序的
(3)key是不可以重覆的,如果遇到重覆,後一個value會替換前一個value
(4)value可以重覆的
package main
import "fmt"
func main(){
//定義map變數:
var a map[int]string
//只聲明map記憶體是沒有分配空間
//必須通過make函數進行初始化,才會分配空間:
a = make(map[int]string,10) //map可以存放10個鍵值對
//將鍵值對存入map中:
a[20095452] = "張三"
a[20095387] = "李四"
a[20097291] = "王五"
a[20095387] = "朱六"
a[20096699] = "張三"
//輸出集合
fmt.Println(a)
}
2.創建
package main
import "fmt"
func main(){
//方式1:
//定義map變數:
var a map[int]string
//只聲明map記憶體是沒有分配空間
//必須通過make函數進行初始化,才會分配空間:
a = make(map[int]string,10) //map可以存放10個鍵值對
//將鍵值對存入map中:
a[20095452] = "張三"
a[20095387] = "李四"
//輸出集合
fmt.Println(a)
//方式2:
b := make(map[int]string)
b[20095452] = "張三"
b[20095387] = "李四"
fmt.Println(b)
//方式3:
c := map[int]string{
20095452 : "張三",
20098765 : "李四",
}
c[20095387] = "王五"
fmt.Println(c)
}
3.操作
1】增加和更新操作:
map["key"]= value ——》 如果key還沒有,就是增加,如果key存在就是修改。
【2】刪除操作:
delete(map,"key") , delete是一個內置函數,如果key存在,就刪除該key-value,如果k的y不存在,不操作,但是也不會報錯
【3】清空操作:
(1)如果我們要刪除map的所有key ,沒有一個專門的方法一次刪除,可以遍歷一下key,逐個刪除
(2)或者map = make(...),make一個新的,讓原來的成為垃圾,被gc回收
【4】查找操作:
value ,bool = map[key]
value為返回的value,bool為是否返回 ,要麼true 要麼false
package main
import "fmt"
func main(){
//定義map
b := make(map[int]string)
//增加:
b[20095452] = "張三"
b[20095387] = "李四"
//修改:
b[20095452] = "王五"
//刪除:
delete(b,20095387)
delete(b,20089546)
fmt.Println(b)
//查找:
value,flag := b[200]
fmt.Println(value)
fmt.Println(flag)
}
【5】獲取長度:len函數
【6】遍歷:for-range
package main
import "fmt"
func main(){
//定義map
b := make(map[int]string)
//增加:
b[20095452] = "張三"
b[20095387] = "李四"
b[20098833] = "王五"
//獲取長度:
fmt.Println(len(b))
//遍歷:
for k,v := range b {
fmt.Printf("key為:%v value為%v \t",k,v)
}
fmt.Println("---------------------------")
//加深難度:
a := make(map[string]map[int]string)
//賦值:
a["班級1"] = make(map[int]string,3)
a["班級1"][20096677] = "露露"
a["班級1"][20098833] = "麗麗"
a["班級1"][20097722] = "菲菲"
a["班級2"] = make(map[int]string,3)
a["班級2"][20089911] = "小明"
a["班級2"][20085533] = "小龍"
a["班級2"][20087244] = "小飛"
for k1,v1:= range a {
fmt.Println(k1)
for k2,v2:= range v1{
fmt.Printf("學生學號為:%v 學生姓名為%v \t",k2,v2)
}
fmt.Println()
}
}
十三、對象
1.對象的引入
【1】Golang語言面向對象編程說明:
(1)Golang也支持面向對象編程(OOP),但是和傳統的面向對象編程有區別,並不是純粹的面向對象語言。所以我們說Golang支持面向對象編程特性是比較準確的。
(2)Golang沒有類(class),Go語言的結構體(struct)和其它編程語言的類(class)有同等的地位,你可以理解Gelang是基於struct來實現OOP特性的。
(3)Golang面向對象編程非常簡潔,去掉了傳統OOP語言的方法重載、構造函數和析構函數、隱藏的this指針等等
(4)Golang仍然有面向對象編程的繼承,封裝和多態的特性,只是實現的方式和其它OOP語言不一樣,比如繼承:Golang沒有extends 關鍵字,繼承是通過匿名欄位來實現。
【2】結構體的引入:
具體的對象:
一位老師:郜宇博老師: 姓名:郜宇博 年齡:22歲 性別 :男 ......
可以使用變數來處理:
package main
import "fmt"
func main(){
//郜宇博老師: 姓名:郜宇博 年齡:22歲 性別 :男 ......
var name string = "郜宇博"
var age int = 22
var sex string = "男"
//馬士兵老師:
var name2 string = "馬士兵"
var age2 int = 45
var sex2 string = "男"
}
缺點:
(1)不利於數據的管理、維護
(2)老師的很多屬性屬於一個對象,用變數管理太分散了
2.結構體
代碼:
package main
import "fmt"
//定義老師結構體,將老師中的各個屬性 統一放入結構體中管理:
type Teacher struct{
//變數名字大寫外界可以訪問這個屬性
Name string
Age int
School string
}
func main(){
//創建老師結構體的實例、對象、變數:
var t1 Teacher // var a int
fmt.Println(t1) //在未賦值時預設值:{ 0 }
t1.Name = "馬士兵"
t1.Age = 45
t1.School = "清華大學"
fmt.Println(t1)
fmt.Println(t1.Age + 10)
}
3.結構體的創建
1.直接創建
2.附帶初始值
3.結構體指針創建
4.結構體之間轉換
【1】結構體是用戶單獨定義的類型,和其它類型進行轉換時需要有完全相同的欄位(名字、個數和類型)
package main
import "fmt"
type Student struct {
Age int
}
type Person struct {
Age int
}
func main(){
var s Student = Student{10}
var p Person = Person{10}
s = Student(p)
fmt.Println(s)
fmt.Println(p)
}
【2】結構體進行type重新定義(相當於取別名),Golang認為是新的數據類型,但是相互間可以強轉
package main
import "fmt"
type Student struct {
Age int
}
type Stu Student
func main(){
var s1 Student = Student{19}
var s2 Stu = Stu{19}
s1 = Student(s2)
fmt.Println(s1)
fmt.Println(s2)
}
5.方法的引入
【1】方法是作用在指定的數據類型上、和指定的數據類型綁定,因此自定義類型,都可以有方法,而不僅僅是struct
【2】方法的聲明和調用格式:
聲明:
type A struct {
Num int
}
func (a A) test() {
fmt.Println(a.Num)
}
調用:
var a A
a.test()
(1)func (a A) test()相當於A結構體有一個方法叫test
(2)(a A)體現方法test和結構體A綁定關係
(3)代碼層面:
註意:
(1)test方法中參數名字隨意起
(2)結構體Person和test方法綁定,調用test方法必須靠指定的類型:Person
(3)如果其他類型變數調用test方法一定會報錯。
(4)結構體對象傳入test方法中,值傳遞,和函數參數傳遞一致。
6.方法的註意事項
(1)結構體類型是值類型,在方法調用中,遵守值類型的傳遞機制,是值拷貝傳遞方式
(2)如程式員希望在方法中,改變結構體變數的值,可以通過結構體指針的方式來處理
我們寫程式的時候,可以直接簡化:
底層編譯器做了優化,底層會自動幫我們加上 & *
(3)Golang中的方法作用在指定的數據類型上的,和指定的數據類型綁定,因此自定義類型,都可以有方法,而不僅僅是struct,比如int , float32等都可以有方法
package main
import "fmt"
type integer int
func (i integer) print(){
i = 30
fmt.Println("i = ",i)
}
func (i *integer) change(){
*i = 30
fmt.Println("i = ",*i)
}
func main(){
var i integer = 20
i.print()
i.change()
fmt.Println(i)
}
(4)方法的訪問範圍控制的規則,和函數一樣。方法名首字母小寫,只能在本包訪問,方法首字母大寫,可以在本包和其它包訪問。
(5)如果一個類型實現了String()這個方法,那麼fmt.Println預設會調用這個變數的String()進行輸出
以後定義結構體的話,常定義String()作為輸出結構體信息的方法,在fmt.Println會自動調用
package main
import "fmt"
type Student struct{
Name string
Age int
}
func (s *Student) String() string{
str := fmt.Sprintf("Name = %v , Age = %v",s.Name,s.Age)
return str
}
func main(){
stu := Student{
Name : "麗麗",
Age : 20,
}
//傳入地址,如果綁定了String方法就會自動調用
fmt.Println(&stu)
}
7.方法和函數的區別
【1】綁定指定類型:
方法:需要綁定指定數據類型
函數:不需要綁定數據類型
【2】調用方式不一樣:
函數的調用方式:
函數名(實參列表)
方法的調用方式:變數.方法名(實參列表)
package main
import "fmt"
type Student struct{
Name string
}
//定義方法:
func (s Student) test01(){
fmt.Println(s.Name)
}
//定義函數:
func method01(s Student){
fmt.Println(s.Name)
}
func main(){
//調用函數:
var s Student = Student{"麗麗"}
method01(s)
//方法調用:
s.test01()
}
【3】對於函數來說,參數類型對應是什麼就要傳入什麼。
package main
import "fmt"
type Student struct{
Name string
}
//定義函數:
func method01(s Student){
fmt.Println(s.Name)
}
func method02(s *Student){
fmt.Println((*s).Name)
}
func main(){
var s Student = Student{"麗麗"}
method01(s)
//method01(&s)錯誤
method02(&s)
//method02(s)錯誤
}
【4】對於方法來說,接收者為值類型,可以傳入指針類型,接受者為指針類型,可以傳入值類型。
package main
import "fmt"
type Student struct{
Name string
}
//定義方法:
func (s Student) test01(){
fmt.Println(s.Name)
}
func (s *Student) test02(){
fmt.Println((*s).Name)
}
func main(){
var s Student = Student{"麗麗"}
s.test01()
(&s).test01()//雖然用指針類型調用,但是傳遞還是按照值傳遞的形式
(&s).test02()
s.test02()//等價
}
8.創建結構體時初始化
【1】方式1:按照順序賦值操作
缺點:必須按照順序有局限性
【2】方式2:按照指定類型
【3】方式3:想要返回結構體的指針類型