<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 4.5 基本類型和運算符 我們將在這個部分講解有關布爾型、數字型和字符型的相關知識。 表達式是一種特定的類型的值,它可以由其它的值以及運算符組合而成。每個類型都定義了可以和自己結合的運算符集合,如果你使用了不在這個集合中的運算符,則會在編譯時獲得編譯錯誤。 一元運算符只可以用于一個值的操作(作為后綴),而二元運算符則可以和兩個值或者操作數結合(作為中綴)。 只有兩個類型相同的值才可以和二元運算符結合,另外要注意的是,Go 是強類型語言,因此不會進行隱式轉換,任何不同類型之間的轉換都必須顯式說明(第 4.2 節)。Go 不存在像 C 和 Java 那樣的運算符重載,表達式的解析順序是從左至右。 你可以在第 4.5.3 節找到有關運算符優先級的相關信息,優先級越高的運算符在條件相同的情況下將被優先執行。但是你可以通過使用括號將其中的表達式括起來,以人為地提升某個表達式的運算優先級。 ## 4.5.1 布爾類型 bool 一個簡單的例子:`var b bool = true`。 布爾型的值只可以是常量 true 或者 false。 兩個類型相同的值可以使用相等 `==` 或者不等 `!=` 運算符來進行比較并獲得一個布爾型的值。 當相等運算符兩邊的值是完全相同的值的時候會返回 true,否則返回 false,并且只有在兩個的值的類型相同的情況下才可以使用。 示例: ``` var aVar = 10 aVar == 5 -> false aVar == 10 -> true ``` 當不等運算符兩邊的值是不同的時候會返回 true,否則返回 false。 示例: ``` var aVar = 10 aVar != 5 -> true aVar != 10 -> false ``` Go 對于值之間的比較有非常嚴格的限制,只有兩個類型相同的值才可以進行比較,如果值的類型是接口(interface,第 11 章),它們也必須都實現了相同的接口。如果其中一個值是常量,那么另外一個值的類型必須和該常量類型相兼容的。如果以上條件都不滿足,則其中一個值的類型必須在被轉換為和另外一個值的類型相同之后才可以進行比較。 布爾型的常量和變量也可以通過和邏輯運算符(非 `!`、和 `&&`、或 `||`)結合來產生另外一個布爾值,這樣的邏輯語句就其本身而言,并不是一個完整的 Go 語句。 邏輯值可以被用于條件結構中的條件語句(第 5 章),以便測試某個條件是否滿足。另外,和 `&&`、或 `||` 與相等 `==` 或不等 `!=` 屬于二元運算符,而非 `!` 屬于一元運算符。在接下來的內容中,我們會使用 T 來代表條件符合的語句,用 F 來代表條件不符合的語句。 Go 語言中包含以下邏輯運算符: 非運算符:`!` ``` !T -> false !F -> true ``` 非運算符用于取得和布爾值相反的結果。 和運算符:`&&` ``` T && T -> true T && F -> false F && T -> false F && F -> false ``` 只有當兩邊的值都為 true 的時候,和運算符的結果才是 true。 或運算符:`||` ``` T || T -> true T || F -> true F || T -> true F || F -> false ``` 只有當兩邊的值都為 false 的時候,或運算符的結果才是 false,其中任意一邊的值為 true 就能夠使得該表達式的結果為 true。 在 Go 語言中,&& 和 || 是具有快捷性質的運算符,當運算符左邊表達式的值已經能夠決定整個表達式的值的時候(&& 左邊的值為 false,|| 左邊的值為 true),運算符右邊的表達式將不會被執行。利用這個性質,如果你有多個條件判斷,應當將計算過程較為復雜的表達式放在運算符的右側以減少不必要的運算。 利用括號同樣可以升級某個表達式的運算優先級。 在格式化輸出時,你可以使用 `%t` 來表示你要輸出的值為布爾型。 布爾值(以及任何結果為布爾值的表達式)最常用在條件結構的條件語句中,例如:if、for 和 switch 結構(第 5 章)。 對于布爾值的好的命名能夠很好地提升代碼的可讀性,例如以 `is` 或者 `Is` 開頭的`isSorted`、`isFinished`、`isVisivle`,使用這樣的命名能夠在閱讀代碼的獲得閱讀正常語句一樣的良好體驗,例如標準庫中的 `unicode.IsDigit(ch)`(第 4.5.5 節)。 ## 4.5.2 數字類型 ### 4.5.2.1 整型 int 和浮點型 float Go 語言支持整型和浮點型數字,并且原生支持復數,其中位的運算采用補碼(詳情參見 [二的補碼](http://en.wikipedia.org/wiki/Two's_complement) 頁面)。 Go 也有基于架構的類型,例如:int、uint 和 uintptr。 這些類型的長度都是根據運行程序所在的操作系統類型所決定的: - `int` 和 `uint` 在 32 位操作系統上,它們均使用 32 位(4 個字節),在 64 位操作系統上,它們均使用 64 位(8 個字節)。 - `uintptr` 的長度被設定為足夠存放一個指針即可。 Go 語言中沒有 float 類型。 與操作系統架構無關的類型都有固定的大小,并在類型的名稱中就可以看出來: 整數: - 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) 無符號整數: - uint8(0 -> 255) - uint16(0 -> 65,535) - uint32(0 -> 4,294,967,295) - uint64(0 -> 18,446,744,073,709,551,615) 浮點型(IEEE-754 標準): - float32(+- 1e-45 -> +- 3.4 \* 1e38) - float64(+- 5 *1e-324 -> 107* 1e308) int 型是計算最快的一種類型。 整型的零值為 0,浮點型的零值為 0.0。 float32 精確到小數點后 7 位,float64 精確到小數點后 15 位。由于精確度的緣故,你在使用 `==` 或者 `!=` 來比較浮點數時應當非常小心。你最好在正式使用前測試對于精確度要求較高的運算。 你應該盡可能地使用 float64,因為 `math` 包中所有有關數學運算的函數都會要求接收這個類型。 你可以通過增加前綴 0 來表示 8 進制數(如:077),增加前綴 0x 來表示 16 進制數(如:0xFF),以及使用 e 來表示 10 的連乘(如: 1e3 = 1000,或者 6.022e23 = 6.022 x 1e23)。 你可以使用 `a := uint64(0)` 來同時完成類型轉換和賦值操作,這樣 a 的類型就是 uint64。 Go 中不允許不同類型之間的混合使用,但是對于常量的類型限制非常少,因此允許常量之間的混合使用,下面這個程序很好地解釋了這個現象(該程序無法通過編譯): 示例 4.8 [type\_mixing.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/type_mixing.go) ``` package main func main() { var a int var b int32 a = 15 b = a + a // 編譯錯誤 b = b + 5 // 因為 5 是常量,所以可以通過編譯 } ``` 如果你嘗試編譯該程序,則將得到編譯錯誤 `cannot use a + a (type int) as type int32 in assignment`。 同樣地,int16 也不能夠被隱式轉換為 int32。 下面這個程序展示了通過顯示轉換來避免這個問題(第 4.2 節)。 示例 4.9 [casting.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/casting.go) ``` package main import "fmt" func main() { var n int16 = 34 var m int32 // compiler error: cannot use n (type int16) as type int32 in assignment //m = n m = int32(n) fmt.Printf("32 bit int is: %d\n", m) fmt.Printf("16 bit int is: %d\n", n) } ``` 輸出: ``` 32 bit int is: 34 16 bit int is: 34 ``` **格式化說明符** 在格式化字符串里,`%d` 用于格式化整數(`%x` 和 `%X` 用于格式化 16 進制表示的數字),`%g` 用于格式化浮點型(`%f` 輸出浮點數,`%e` 輸出科學計數表示法),`%0d` 用于規定輸出定長的整數,其中開頭的數字 0 是必須的。 `%n.mg` 用于表示數字 n 并精確到小數點后 m 位,除了使用 g 之外,還可以使用 e 或者 f,例如:使用格式化字符串`%5.2e` 來輸出 3.4 的結果為 `3.40e+00`。 **數字值轉換** 當進行類似 `a32bitInt = int32(a32Float)` 的轉換時,小數點后的數字將被丟棄。這種情況一般發生當從取值范圍較大的類型轉換為取值范圍較小的類型時,或者你可以寫一個專門用于處理類型轉換的函數來確保沒有發生精度的丟失。下面這個例子展示如何安全地從 int 型轉換為 int8: ``` func Uint8FromInt(n int) (uint8, error) { if 0 <= n && n <= math.MaxUint8 { // conversion is safe return uint8(n), nil } return 0, fmt.Errorf("%d is out of the uint8 range", n) } ``` 或者安全地從 float64 轉換為 int: ``` func IntFromFloat64(x float64) int { if math.MinInt32 <= x && x <= math.MaxInt32 { // x lies in the integer range whole, fraction := math.Modf(x) if fraction >= 0.5 { whole++ } return int(whole) } panic(fmt.Sprintf("%g is out of the int32 range", x)) } ``` 不過如果你實際存的數字超出你要轉換到的類型的取值范圍的話,則會引發 panic(第 13.2 節)。 **問題 4.1** int 和 int64 是相同的類型嗎? ### 4.5.2.2 復數 Go 擁有以下復數類型: ``` complex64 (32 位實數和虛數) complex128 (64 位實數和虛數) ``` 復數使用 `re+imI` 來表示,其中 `re` 代表實數部分,`im` 代表虛數部分,I 代表根號負 1。 示例: ``` var c1 complex64 = 5 + 10i fmt.Printf("The value is: %v", c1) // 輸出: 5 + 10i ``` 如果 `re` 和 `im` 的類型均為 float32,那么類型為 complex64 的復數 c 可以通過以下方式來獲得: ``` c = complex(re, im) ``` 函數 `real(c)` 和 `imag(c)` 可以分別獲得相應的實數和虛數部分。 在使用格式化說明符時,可以使用 `%v` 來表示復數,但當你希望只表示其中的一個部分的時候需要使用 `%f`。 復數支持和其它數字類型一樣的運算。當你使用等號 `==` 或者不等號 `!=` 對復數進行比較運算時,注意對精確度的把握。`cmath` 包中包含了一些操作復數的公共方法。如果你對內存的要求不是特別高,最好使用 complex128 作為計算類型,因為相關函數都使用這個類型的參數。 ### 4.5.2.3 位運算 位運算只能用于整數類型的變量,且需當它們擁有等長位模式時。 `%b` 是用于表示位的格式化標識符。 **二元運算符** - 按位與 `&`: 對應位置上的值經過和運算結果,具體參見和運算符,第 4.5.1 節,并將 T(true)替換為 1,將 F(false)替換為 0 ``` 1 & 1 -> 1 1 & 0 -> 0 0 & 1 -> 0 0 & 0 -> 0 ``` - 按位或 `|`: 對應位置上的值經過或運算結果,具體參見或運算符,第 4.5.1 節,并將 T(true)替換為 1,將 F(false)替換為 0 ``` 1 | 1 -> 1 1 | 0 -> 1 0 | 1 -> 1 0 | 0 -> 0 ``` - 按位異或 `^`: 對應位置上的值根據以下規則組合: ``` 1 ^ 1 -> 0 1 ^ 0 -> 1 0 ^ 1 -> 1 0 ^ 0 -> 0 ``` - 位清除 `&^`:將指定位置上的值設置為 0。 **一元運算符** - 按位補足 `^`: 該運算符與異或運算符一同使用,即 `m^x`,對于無符號 x 使用“全部位設置為 1”,對于有符號 x 時使用 `m=-1`。例如: ``` ^2 = ^10 = -01 ^ 10 = -11 ``` - 位左移 `<<`: - 用法:`bitP << n`。 - `bitP` 的位向左移動 n 位,右側空白部分使用 0 填充;如果 n 等于 2,則結果是 2 的相應倍數,即 2 的 n 次方。例如: ``` 1 << 10 // 等于 1 KB 1 << 20 // 等于 1 MB 1 << 30 // 等于 1 GB ``` - 位右移 `>>`: - 用法:`bitP >> n`。 - `bitP` 的位向右移動 n 位,左側空白部分使用 0 填充;如果 n 等于 2,則結果是當前值除以 2 的 n 次方。 當希望把結果賦值給第一個操作數時,可以簡寫為 `a <<= 2` 或者 `b ^= a & 0xffffffff`。 **位左移常見實現存儲單位的用例** 使用位左移與 iota 計數配合可優雅地實現存儲單位的常量枚舉: ``` type ByteSize float64 const ( _ = iota // 通過賦值給空白標識符來忽略值 KB ByteSize = 1<<(10*iota) MB GB TB PB EB ZB YB ) ``` **在通訊中使用位左移表示標識的用例** ``` type BitFlag int const ( Active BitFlag = 1 << iota // 1 << 0 == 1 Send // 1 << 1 == 2 Receive // 1 << 2 == 4 ) flag := Active | Send // == 3 ``` ### 4.5.2.4 邏輯運算符 Go 中擁有以下邏輯運算符:`==`、`!=`(第 4.5.1 節)、`<`、`<=`、`>`、`>=`。 它們之所以被稱為邏輯運算符是因為它們的運算結果總是為布爾值 `bool`。例如: ``` b3:= 10 > 5 // b3 is true ``` ### 4.5.2.5 算術運算符 常見可用于整數和浮點數的二元運算符有 `+`、`-`、`*` 和 `/`。 (相對于一般規則而言,Go 在進行字符串拼接時允許使用對運算符 `+` 的重載,但 Go 本身不允許開發者進行自定義的運算符重載) `/` 對與整數運算而言,結果依舊為整數,例如:`9 / 4 -> 2`。 取余運算符只能作用于整數:`9 % 4 -> 1`。 整數除以 0 可能導致程序崩潰,將會導致運行時的恐慌狀態(如果除以 0 的行為在編譯時就能被捕捉到,則會引發編譯錯誤);第 13 章將會詳細講解如何正確地處理此類情況。 浮點數除以 0.0 會返回一個無窮盡的結果,使用 `+Inf` 表示。 **練習 4.4** 嘗試編譯 [divby0.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_4/divby0.go)。 你可以將語句 `b = b + a` 簡寫為 `b+=a`,同樣的寫法也可用于 `-=`、`*=`、`/=`、`%=`。 對于整數和浮點數,你可以使用一元運算符 `++`(遞增)和 `--`(遞減),但只能用于后綴: ``` i++ -> i += 1 -> i = i + 1 i-- -> i -= 1 -> i = i - 1 ``` 同時,帶有 `++` 和 `--` 的只能作為語句,而非表達式,因此 `n = i++` 這種寫法是無效的,其它像 `f(i++)` 或者`a[i]=b[i++]` 這些可以用于 C、C++ 和 Java 中的寫法在 Go 中也是不允許的。 在運算時 **溢出** 不會產生錯誤,Go 會簡單地將超出位數拋棄。如果你需要范圍無限大的整數或者有理數(意味著只被限制于計算機內存),你可以使用標準庫中的 `big` 包,該包提供了類似 `big.Int` 和 `big.Rat` 這樣的類型(第 9.4 節)。 ### 4.5.2.6 隨機數 一些像游戲或者統計學類的應用需要用到隨機數。`rand` 包實現了偽隨機數的生成。 示例 4.10 [random.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/random.go) 演示了如何生成 10 個非負隨機數: ``` package main import ( "fmt" "math/rand" "time" ) func main() { for i := 0; i < 10; i++ { a := rand.Int() fmt.Printf("%d / ", a) } for i := 0; i < 5; i++ { r := rand.Intn(8) fmt.Printf("%d / ", r) } fmt.Println() timens := int64(time.Now().Nanosecond()) rand.Seed(timens) for i := 0; i < 10; i++ { fmt.Printf("%2.2f / ", 100*rand.Float32()) } } ``` 可能的輸出: ``` 816681689 / 1325201247 / 623951027 / 478285186 / 1654146165 / 1951252986 / 2029250107 / 762911244 / 1372544545 / 591415086 / / 3 / 0 / 6 / 4 / 2 /22.10 / 65.77 / 65.89 / 16.85 / 75.56 / 46.90 / 55.24 / 55.95 / 25.58 / 70.61 / ``` 函數 `rand.Float32` 和 `rand.Float64` 返回介于 \[0.0, 1.0) 之間的偽隨機數,其中包括 0.0 但不包括 1.0。函數 `rand.Intn`返回介于 \[0, n) 之間的偽隨機數。 你可以使用 `Seed(value)` 函數來提供偽隨機數的生成種子,一般情況下都會使用當前時間的納秒級數字(第 4.8 節)。 ## 4.5.3 運算符與優先級 有些運算符擁有較高的優先級,二元運算符的運算方向均是從左至右。下表列出了所有運算符以及它們的優先級,由上至下代表優先級由高到低: ``` 優先級 運算符 7 ^ ! 6 * / % << >> & &^ 5 + - | ^ 4 == != < <= >= > 3 <- 2 && 1 || ``` 當然,你可以通過使用括號來臨時提升某個表達式的整體運算優先級。 ## 4.5.4 類型別名 當你在使用某個類型時,你可以給它起另一個名字,然后你就可以在你的代碼中使用新的名字(用于簡化名稱或解決名稱沖突)。 在 `type TZ int` 中,TZ 就是 int 類型的新名稱(用于表示程序中的時區),然后就可以使用 TZ 來操作 int 類型的數據。 示例 4.11 [type.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/type.go) ``` package main import "fmt" type TZ int func main() { var a, b TZ = 3, 4 c := a + b fmt.Printf("c has the value: %d", c) // 輸出:c has the value: 7 } ``` 實際上,類型別名得到的新類型并非和原類型完全相同,新類型不會擁有原類型所附帶的方法(第 10 章);TZ 可以自定義一個方法用來輸出更加人性化的時區信息。 **練習 4.5** 定義一個 `string` 的類型別名 `Rope`,并聲明一個該類型的變量。 ## 4.5.5 字符類型 嚴格來說,這并不是 Go 語言的一個類型,字符只是整數的特殊用例。`byte` 類型是 `uint8` 的別名,對于只占用 1 個字節的傳統 ASCII 編碼的字符來說,完全沒有問題。例如:`var ch byte = 'A'`;字符使用單引號括起來。 在 ASCII 碼表中,A 的值是 65,而使用 16 進制表示則為 41,所以下面的寫法是等效的: ``` var ch byte = 65 或 var ch byte = '\x41' ``` (`\x` 總是緊跟著長度為 2 的 16 進制數) 另外一種可能的寫法是 `\` 后面緊跟著長度為 3 的十進制數,例如:`\377`。 不過 Go 同樣支持 Unicode(UTF-8),因此字符同樣稱為 Unicode 代碼點或者 runes,并在內存中使用 int 來表示。在文檔中,一般使用格式 U+hhhh 來表示,其中 h 表示一個 16 進制數。其實 `rune` 也是 Go 當中的一個類型,并且是 `int32`的別名。 在書寫 Unicode 字符時,需要在 16 進制數之前加上前綴 `\u` 或者 `\U`。 因為 Unicode 至少占用 2 個字節,所以我們使用 `int16` 或者 `int` 類型來表示。如果需要使用到 4 字節,則會加上 `\U`前綴;前綴 `\u` 則總是緊跟著長度為 4 的 16 進制數,前綴 `\U` 緊跟著長度為 8 的 16 進制數。 示例 4.12 [char.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/char.go) ``` var ch int = '\u0041' var ch2 int = '\u03B2' var ch3 int = '\U00101234' fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point ``` 輸出: ``` 65 - 946 - 1053236 A - β - r 41 - 3B2 - 101234 U+0041 - U+03B2 - U+101234 ``` 格式化說明符 `%c` 用于表示字符;當和字符配合使用時,`%v` 或 `%d` 會輸出用于表示該字符的整數;`%U` 輸出格式為 U+hhhh 的字符串(另一個示例見第 5.4.4 節)。 包 `unicode` 包含了一些針對測試字符的非常有用的函數(其中 `ch` 代表字符): - 判斷是否為字母:`unicode.IsLetter(ch)` - 判斷是否為數字:`unicode.IsDigit(ch)` - 判斷是否為空白符號:`unicode.IsSpace(ch)` 這些函數返回一個布爾值。包 `utf8` 擁有更多與 rune 相關的函數。 ( **譯者注:關于類型的相關講解,可參考視頻教程 《Go編程基礎》 第 3 課:[類型與變量](https://github.com/Unknwon/go-fundamental-programming/blob/master/lectures/lecture3.md)** )
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看