天天看點

go 從入門到精通(二)基本資料類型和操作符

一、檔案名&關鍵字&辨別符

  • 所有go源碼都是以.go結尾
  • 辨別符以字母或下劃線開頭,大小寫敏感
  • 下劃線_是特殊辨別符,使用者忽略結果
  • 保留關鍵字
  • 導入包時可以設定别名

下面是保留關鍵字:

go 從入門到精通(二)基本資料類型和操作符

二、GO程式的基本結構

package main

import (
    "fmt"
)

func main(){
    fmt.Println("Hello world")
}      
  1. 任何一個代碼必須隸屬一個包
  2. import關鍵字,引入其他包
  3. golang可執行程式,package main 并且隻有一個main入口函數
  4. 包中函數的調用,同一個函數中可以直接調用;不同包中函數,通過包名+點+函數名進行調用
  5. 包通路控制規則,大寫意味着這個函數或者變量可以導出的,及在其他包内是可以調用的;小寫以為這個函數或者變量是私有的,包外部不能通路。

小練習1

寫一個小程式,對于給定的一個數字n,求出所有兩兩相加等于n的組合

package main

import (
    "fmt"
)

func add_num(n int){
    for i:=0;i<=n;i++{
        fmt.Printf("%d+%d=%d\n",i,n-i,n)
    }
}

func main(){
    add_num(5)
}      

小練習2

寫一個小程式,包含兩個包,add和main,其中add包中有兩個變量:Name,和age,請問main包中如何通路Name和age?(用于了解go中大小寫敏感的問題)

main包中的代碼:

package main 
import (
    "fmt"
    "go_dev/day02/kexia02/add"
)

func main() {
    fmt.Println(add.Name)
}      

add包中的代碼

package add  
var Name string = "zhaofan"
var age int = 23      

從結果我們可以發現我們在main包中是不能調用到add包中的age,但是是可以調用到Name

這裡就是因為大小寫的問題,go中的大寫可以了解為其他語言中的public,小寫了解為private

這裡有個問題需要注意:

我們把add包中的代碼改為:

package add
var Name string
var Age int

Name = "zhaofan"
Age = 23      

這樣也是錯誤的寫法,go作為編譯型語言,必須通過函數來進行語句的執行,而不能在函數外執行語句

小練習3

開發一個小程式,使用包别名來通路包中的函數或變量

直接對上一個程式的main包進行更改

package main

import (
    "fmt"
    a "go_dev/day02/kexia02/add"
)

func main() {
    fmt.Println(a.Name)
    fmt.Println(a.Age)
}      

小練習4

每個源檔案都可以包含一個init函數,這個init函數自動被go運作架構調用,通過下面例子示範:

package main

import (
    "fmt"
)

func init(){
    fmt.Println("執行初始化函數")
}

func main() {
    fmt.Println("hello world")
}      

運作結果是先列印了init函數的内容,後列印了main函數中的問題,是以init函數先與main函數執行

三、函數的聲明和注釋

函數聲明

格式為:func 函數名字(參數清單)(傳回值清單)

例子如下:

func add(){

}

func add(a int,b int) int{

func add(a int,b int) (int int){

注釋

單行注釋//

多行注釋/* */

四、GO語言的資料類型和操作符

常見資料類型及分類

GO語言按照類别分為幾下幾種資料類型:

布爾型:true或false,例子:var b bool = true

數字類型:包括整型int和浮點float

字元串類型:這裡強調一下,GO的字元串是由單個位元組連接配接起來的Go語言的字元串的位元組使用UTF-8編碼辨別Unicode文本。

派生類型:這裡包括指針類型,數組類型,結構化類型,Channel類型,函數類型,接口類型,Map類型

注意:

字元串的時候用雙引号”“,這裡也可以用反引号`,通過反引号的方式會保留你的格式,不會對你的内容做任何轉義

位元組的時候用單引号‘’,同樣也可以通過反引号`

var cc byte = 'c' fmt.println(ccc)

var cc byte = 

c

 fmt.println(cc)

一個會列印c的ASCII,一個會列印c

關于fmt.Printf()的用法

官網位址:https://go-zh.org/pkg/fmt/

一般

%v 相應值的預設格式。在列印結構體時,“加号”标記(%+v)會添加字段名

%#v 相應值的Go文法表示

%T 相應值的類型的Go文法表示

%% 字面上的百分号,并非值的占位符

布爾

%t 單詞 true 或 false。

整數

%b 二進制表示

%c 相應Unicode碼點所表示的字元

%d 十進制表示

%o 八進制表示

%q 單引号圍繞的字元字面值,由Go文法安全地轉義

%x 十六進制表示,字母形式為小寫 a-f

%X 十六進制表示,字母形式為大寫 A-F

%U Unicode格式:U+1234,等同于 "U+%04X"

浮點數及其複合構成

%b 無小數部分的,指數為二的幂的科學計數法,與 strconv.FormatFloat

的 'b' 轉換格式一緻。例如 -123456p-78

%e 科學計數法,例如 -1234.456e+78

%E 科學計數法,例如 -1234.456E+78

%f 有小數點而無指數,例如 123.456

%g 根據情況選擇 %e 或 %f 以産生更緊湊的(無末尾的0)輸出

%G 根據情況選擇 %E 或 %f 以産生更緊湊的(無末尾的0)輸出

字元串與位元組切片

%s 字元串或切片的無解譯位元組

%q 雙引号圍繞的字元串,由Go文法安全地轉義

%x 十六進制,小寫字母,每位元組兩個字元

%X 十六進制,大寫字母,每位元組兩個字元

指針

%p 十六進制表示,字首 0x

通過fmt.Printf() 可以格式化輸出到終端,如果想要格式化存儲到變量則是fmt.Sprintf()

數字類型

數字類型包括了:

uint8(無符号8位整型,0到255)

uint16(無符号16位整型,0到65535)

uint32(無符号32位整型,0到4294967295)

unint64(無符号64位整型,0到18446744073709551615)

int8(有符号8位整型,-128到127)

int16(有符号16位整型,-32768到32767)

int32(有符号32位整型 ,-2147483648 到 2147483647)

int64(有符号64位整型 ,-9223372036854775808到9223372036854775807)

浮點型

flat32: 32位浮點型數

flag64: 64位浮點型數

complex64:32 位實數和虛數

complex128:64 位實數和虛數

類型轉換

舉個例子來了解: var a int = 8 轉換為int32 var b int32 = int32(a)

當我們代碼中設計到資料計算的時候,要保證兩個資料類型完全相同,

var a int 和 var b int32 是不能直接做計算處理的,這個時候就需要用到類型轉換

相關操作符

! && || 分别表示非,與,或

== 、=、!=、 <、>、<=、>=

練習1

使用math/rand生成随機整數,10個小于100的随機整數以及10個随機浮點數

package main

import (
    "fmt"
    "math/rand"
)

func rand_print(){
    for i:=0;i<10;i++{
        fmt.Println(rand.Int31n(100))
        fmt.Println(rand.Float32())
    }


}
func main() {
    rand_print()
}      

但是這裡會造成每次運作程式生成的随機數是相同的,解決方式是加入随機種子:rand.Seed(time.Now().Unix())

五、常量

常用cost修飾,代表永遠是隻讀不能修改

const隻能修飾boolean,number(int相關類型,浮點類型,complex)和string

文法

const 變量名 [變量類型] = value其中變量類型可以省略

例子

const b string = "hello"

const b int = 23

通常定義常亮的寫法

const (

a = 0

b = 1

)

進階方法

a = iota

b

c

這裡自動回吧a指派為0,後面的變量一次加1

六、變量

聲明一個變量的形式是使用var關鍵字格式如下:

var 變量名 變量類型

關于變量的聲明常用的有三種方法:

  1. 指定變量類型,聲明變量後不指派,使用預設值。如果是資料類型是int,預設值為0,如果資料類型是字元串string,預設值為空,如果是布爾類型預設為false
  2. 不指定變量類型,根據值自行判斷變量類型(個人不建議這種方法,go是強類型語言,定義變量最好指定變量類型)
  3. 省略var關鍵字通過:=方式定義變量,并指派。例子name := "zhaofan"就相當于var name string然後name = "zhaofan"

變量的作用域

在函數内部聲明的變量叫做局部變量,生命周期僅限于函數内部

在函數外部生命的變量叫做全局變量,生命周期作用域整個包,如果是大寫,作用域整個程式

在函數内的語句塊的内的變量隻在語句塊,生命周期就是僅限于語句塊内.這裡主要指{} 括起來的語句塊

通過下面的例子了解

例子1

package main

import (
    "fmt"
)

var a string = "zhaofan"

func n(){
    fmt.Println(a)
}
func m(){
    a := "Jack"
    fmt.Println(a)
}

func main(){
    n()
    m()
    n()
}      

結果會依次列印zhaofan,Jack,zhaofan

這裡就是驗證了函數内部的定義的變量,生命周期僅限于函數内部

如果我們把m函數中的a:="Jack"改為a = "Jack"

結果為:zhaofan,Jack,Jack

例子2

package main

import (
    "fmt"
)
var a string

func f1(){
    a := "Jack"
    fmt.Println(a)
    f2()
}
func f2(){
    fmt.Println(a)
}
func main(){
    a = "zhaofan"
    fmt.Println(a)
    f1()
}      

這個程式的結果會列印zhaofan,Jack,zhaofan

其實這裡還是要了解上面的說的關于變量的作用域

值類型和引用類型

值類型:變量直接存儲值,即變量直接指向存在記憶體中的值。記憶體通常在棧中配置設定

值類型通常包括基本資料類型int,float,bool,string以及數組和struct

var i int = 5

var j int = i

這個時候i和j的值都為5

其實這裡記憶體中是将i的值進行了拷貝,我們通過&擷取變量的記憶體位址也可以看出

&i和&j 的記憶體位址是不同的,是以我如果在var j int = i,後繼續更改i變量的值,并不會影響j的值,因為是不同的記憶體位址存放的值

引用類型:變量存的是一個位址,這個位址存儲最終的值,記憶體通常在堆上配置設定。通過GC回收

一個引用類型的變量 r1 存儲的是 r1 的值所在的記憶體位址(數字),或記憶體位址中第一個字所在的位置。

引用類型通常包括指針,slice,map,chan等。

是以如果我們定義了兩個引用類型變量像上面的值類型一樣進行指派操作則兩者都會改變,因為兩者的引用位址是相同的。

是以在引用類型中變量是拷貝的記憶體位址,而位址最終指向值

package main

import (
    "fmt"
)

func main()  {
    var a int = 100
    var b chan int = make(chan int,1)
    fmt.Println("a=",a)
    fmt.Println("b=",b)
}      

結果為:

go 從入門到精通(二)基本資料類型和操作符

從這裡我們也可以看出值類型和引用類型的差別

寫一個小程式,交換兩個整數的值

package main

import (
    "fmt"
)

func swap(a int,b int){
    a,b = b,a
    fmt.Println("a=",a,"b=",b)
}

func main() {
    change(5,4)
}      

所有的努力都值得期許,每一份夢想都應該灌溉!