《Go语言圣经》学习笔记 第三章 基础数据类型
《Go語言圣經》學習筆記 第三章 基礎數據類型
目錄
注:學習《Go語言圣經》筆記,PDF點擊下載,建議看書。
Go語言小白學習筆記,書上的內容照搬,大佬看了勿噴,以后熟悉了會總結成自己的讀書筆記。
1. 整型
型。
2. 浮點數
Go語言提供了兩種精度的浮點數, float32和float64。 它們的算術規范由IEEE754浮點數國際標準定義, 該浮點數規范被所有現代的CPU支持。
這些浮點數類型的取值范圍可以從很微小到很巨大。 浮點數的范圍極限值可以在math包找到。 常量math.MaxFloat32表示float32能表示的最大數值, 大約是 3.4e38; 對應的math.MaxFloat64常量大約是1.8e308。 它們分別能表示的最小值近似為1.4e-45和4.9e-324。
一個float32類型的浮點數可以提供大約6個十進制數的精度, 而float64則可以提供約15個十進制數的精度; 通常應該優先使用float64類型, 因為float32類型的累計計算誤差很容易擴散,并且float32能精確表示的正整數并不是很大( 譯注: 因為float32的有效bit位只有23個, 其它的bit位用于指數和符號; 當整數大于23bit能表達的范圍時, float32的表示將出現誤差) :
浮點數的字面值可以直接寫小數部分, 像這樣:
小數點前面或后面的數字都可能被省略( 例如.707或1.) 。 很小或很大的數最好用科學計數法書寫, 通過e或E來指定指數部分:
用Printf函數的%g參數打印浮點數, 將采用更緊湊的表示形式打印, 并提供足夠的精度, 但是對應表格的數據, 使用%e( 帶指數) 或%f的形式打印可能更合適。 所有的這三個打印形式都可以指定打印的寬度和控制打印精度。
上面代碼打印e的冪, 打印精度是小數點后三個小數精度和8個字符寬度:
math包中除了提供大量常用的數學函數外, 還提供了IEEE754浮點數標準中定義的特殊值的創建和測試: 正無窮大和負無窮大, 分別用于表示太大溢出的數字和除零的結果; 還有NaN非數, 一般用于表示無效的除法操作結果0/0或Sqrt(-1).
函數math.IsNaN用于測試一個數是否是非數NaN, math.NaN則返回非數對應的值。 雖然可以用math.NaN來表示一個非法的結果, 但是測試一個結果是否是非數NaN則是充滿風險的, 因為NaN和任何數都是不相等的( 譯注: 在浮點數中, NaN、 正無窮大和負無窮大都不是唯一的, 每個都有非常多種的bit模式表示) :
如果一個函數返回的浮點數結果可能失敗, 最好的做法是用單獨的標志報告失敗, 像這樣:
接下來的程序演示了通過浮點計算生成的圖形。 它是帶有兩個參數的z = f(x, y)函數的三維形式, 使用了可縮放矢量圖形( SVG) 格式輸出, SVG是一個用于矢量線繪制的XML標準。 圖3.1顯示了sin?/r函數的輸出圖形, 其中r是sqrt(xx+yy)。
gopl.io/ch3/surface
// Surface computes an SVG rendering of a 3-D surface function. package mainimport ("fmt""math" )const (width, height = 600, 320 // canvas size in pixelscells = 100 // number of grid cellsxyrange = 30.0 // axis ranges (-xyrange..+xyrange)xyscale = width / 2 / xyrange // pixels per x or y unitzscale = height * 0.4 // pixels per z unitangle = math.Pi / 6 // angle of x, y axes (=30°) )var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)func main() {fmt.Printf("<svg xmlns='http://www.w3.org/2000/svg' "+"style='stroke: grey; fill: white; stroke-width: 0.7' "+"width='%d' height='%d'>", width, height)for i := 0; i < cells; i++ {for j := 0; j < cells; j++ {ax, ay := corner(i+1, j)bx, by := corner(i, j)cx, cy := corner(i, j+1)dx, dy := corner(i+1, j+1)fmt.Printf("<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\n",ax, ay, bx, by, cx, cy, dx, dy)}}fmt.Println("</svg>") }func corner(i, j int) (float64, float64) {// Find point (x,y) at corner of cell (i,j).x := xyrange * (float64(i)/cells - 0.5)y := xyrange * (float64(j)/cells - 0.5)// Compute surface height z.z := f(x, y)// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).sx := width/2 + (x-y)*cos30*xyscalesy := height/2 + (x+y)*sin30*xyscale - z*zscalereturn sx, sy }func f(x, y float64) float64 {r := math.Hypot(x, y) // distance from (0,0)return math.Sin(r) / r }要注意的是corner函數返回了兩個結果, 分別對應每個網格頂點的坐標參數。
要解釋這個程序是如何工作的需要一些基本的幾何學知識, 但是我們可以跳過幾何學原理,因為程序的重點是演示浮點數運算。 程序的本質是三個不同的坐標系中映射關系, 如圖3.2所示。 第一個是100x100的二維網格, 對應整數整數坐標(i,j), 從遠處的(0, 0)位置開始。 我們從遠處向前面繪制, 因此遠處先繪制的多邊形有可能被前面后繪制的多邊形覆蓋。
第二個坐標系是一個三維的網格浮點坐標(x,y,z), 其中x和y是i和j的線性函數, 通過平移轉換位網格單元的中心, 然后用xyrange系數縮放。 高度z是函數f(x,y)的值。
第三個坐標系是一個二維的畫布, 起點(0,0)在左上角。 畫布中點的坐標用(sx, sy)表示。 我們使用等角投影將三維點
(x,y,z)投影到二維的畫布中。 畫布中從遠處到右邊的點對應較大的x值和較大的y值。 并且畫布中x和y值越大, 則對應的z值越小。 x和y的垂直和水平縮放系數來自30度角的正弦和余弦值。z的縮放系數0.4, 是一個任意選擇的參數。
對于二維網格中的每一個網格單元, main函數計算單元的四個頂點在畫布中對應多邊形ABCD的頂點, 其中B對應(i,j)頂點位置, A、 C和D是其它相鄰的頂點, 然后輸出SVG的繪制指令。
3. 復數
Go語言提供了兩種精度的復數類型: complex64和complex128, 分別對應float32和float64兩種浮點數精度。 內置的complex函數用于構建復數, 內建的real和imag函數分別返回復數的實部和虛部:
如果一個浮點數面值或一個十進制整數面值后面跟著一個i, 例如3.141592i或2i, 它將構成一個復數的虛部, 復數的實部是0:
在常量算術規則下, 一個復數常量可以加到另一個普通數值常量( 整數或浮點數、 實部或虛部) , 我們可以用自然的方式書寫復數, 就像1+2i或與之等價的寫法2i+1。 上面x和y的聲明語句還可以簡化:
復數也可以用==和!=進行相等比較。 只有兩個復數的實部和虛部都相等的時候它們才是相等的( 譯注: 浮點數的相等比較是危險的, 需要特別小心處理精度問題) 。
math/cmplx包提供了復數處理的許多函數, 例如求復數的平方根函數和求冪函數。
下面的程序使用complex128復數算法來生成一個Mandelbrot圖像。
gopl.io/ch3/mandelbrot
// Mandelbrot emits a PNG image of the Mandelbrot fractal. package mainimport ("image""image/color""image/png""math/cmplx""os" )func main() {const (xmin, ymin, xmax, ymax = -2, -2, +2, +2width, height = 1024, 1024)img := image.NewRGBA(image.Rect(0, 0, width, height))for py := 0; py < height; py++ {y := float64(py)/height*(ymax-ymin) + yminfor px := 0; px < width; px++ {x := float64(px)/width*(xmax-xmin) + xminz := complex(x, y)// Image point (px, py) represents complex value z.img.Set(px, py, mandelbrot(z))}}png.Encode(os.Stdout, img) // NOTE: ignoring errors }func mandelbrot(z complex128) color.Color {const iterations = 200const contrast = 15var v complex128for n := uint8(0); n < iterations; n++ {v = v*v + zif cmplx.Abs(v) > 2 {return color.Gray{255 - contrast*n}}}return color.Black }//!-// Some other interesting functions:func acos(z complex128) color.Color {v := cmplx.Acos(z)blue := uint8(real(v)*128) + 127red := uint8(imag(v)*128) + 127return color.YCbCr{192, blue, red} }func sqrt(z complex128) color.Color {v := cmplx.Sqrt(z)blue := uint8(real(v)*128) + 127red := uint8(imag(v)*128) + 127return color.YCbCr{128, blue, red} }// f(x) = x^4 - 1 // // z' = z - f(z)/f'(z) // = z - (z^4 - 1) / (4 * z^3) // = z - (z - 1/z^3) / 4 func newton(z complex128) color.Color {const iterations = 37const contrast = 7for i := uint8(0); i < iterations; i++ {z -= (z - 1/(z*z*z)) / 4if cmplx.Abs(z*z*z*z-1) < 1e-6 {return color.Gray{255 - contrast*i}}}return color.Black }用于遍歷1024x1024圖像每個點的兩個嵌套的循環對應-2到+2區間的復數平面。 程序反復測試每個點對應復數值平方值加一個增量值對應的點是否超出半徑為2的圓。 如果超過了, 通過根據預設置的逃逸迭代次數對應的灰度顏色來代替。 如果不是, 那么該點屬于Mandelbrot集合, 使用黑色顏色標記。 最終程序將生成的PNG格式分形圖像圖像輸出到標準輸出, 如圖3.3所示。
4. 布爾型
5. 字符串
一個字符串是一個不可改變的字節序列。 字符串可以包含任意的數據, 包括byte值0, 但是通
常是用來包含人類可讀的文本。 文本字符串通常被解釋為采用UTF8編碼的Unicode碼點
( rune) 序列, 我們稍后會詳細討論這個問題。
內置的len函數可以返回一個字符串中的字節數目( 不是rune字符數目) , 索引操作s[i]返回第i個字節的字節值, i必須滿足0 ≤ i< len(s)條件約束
如果試圖訪問超出字符串索引范圍的字節將會導致panic異常:
第i個字節并不一定是字符串的第i個字符, 因為對于非ASCII字符的UTF8編碼會要兩個或多個字節。 我們先簡單說下字符的工作方式。
子字符串操作s[i:j]基于原始的s字符串的第i個字節開始到第j個字節( 并不包含j本身) 生成一個新字符串。 生成的新字符串將包含j-i個字節。
同樣, 如果索引超出字符串范圍或者j小于i的話將導致panic異常
不管i還是j都可能被忽略, 當它們被忽略時將采用0作為開始位置, 采用len(s)作為結束的位置。
其中+操作符將兩個字符串鏈接構造一個新字符串:
字符串可以用==和<進行比較; 比較通過逐個字節比較完成的, 因此比較的結果是字符串自然編碼的順序。
字符串的值是不可變的: 一個字符串包含的字節序列永遠不會被改變, 當然我們也可以給一個字符串變量分配一個新字符串值。 可以像下面這樣將一個字符串追加到另一個字符串:
這并不會導致原始的字符串值被改變, 但是變量s將因為+=語句持有一個新的字符串值, 但是t依然是包含原先的字符串值。
因為字符串是不可修改的, 因此嘗試修改字符串內部數據的操作也是被禁止的:
不變性意味如果兩個字符串共享相同的底層數據的話也是安全的, 這使得復制任何長度的字符串代價是低廉的。 同樣, 一個字符串s和對應的子字符串切片s[7:]的操作也可以安全地共享相同的內存, 因此字符串切片操作代價也是低廉的。 在這兩種情況下都沒有必要分配新的內存。 圖3.4演示了一個字符串和兩個字串共享相同的底層數據。
1. 字符串面值
| \a | 響鈴 |
| \b | 退格 |
| \f | 換頁 |
| \n | 換行 |
| \r | 回車 |
| \t | 制表符 |
| \v | 垂直制表符 |
| ’ | 單引號 (只用在 ‘’’ 形式的rune符號面值中) |
| " | 雙引號 (只用在 “…” 形式的字符串面值中) |
| \ | 反斜杠 |
2. Unicode
3. UTF-8
總結
以上是生活随笔為你收集整理的《Go语言圣经》学习笔记 第三章 基础数据类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Go语言圣经》学习笔记 第二章 程序结
- 下一篇: 《Hadoop权威指南》第二章 关于Ma