|
xml對應的struct 屬性必須大寫,否則無法實現!
Code是必須的
package main
import (
"encoding/xml"
"fmt"
"os"
)
type xmldas struct {
XMLName xml.Name `xml:"das"`
DataPort string `xml:"DataPort,attr"`
Desc string `xml:"desc,attr"`
Src xmlsource `xml:"source"`
Dest xmldestination `xml:"destination"`
}
type xmlsource struct {
Path string `xml:"path,attr"`
Param string `xml:"param,attr"`
}
type xmldestination struct {
Path string `xml:"path,attr"`
Param string `xml:"param,attr"`
}
func main() {
v := xmldas{DataPort: "8250", Desc: "123"}
v.Src = xmlsource{Path: "123", Param: "456"}
v.Dest = xmldestination{Path: "789", Param: "000"}
output, err := xml.MarshalIndent(v, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
}
os.Stdout.Write([]byte(xml.Header))
os.Stdout.Write(output)
}
將xml文件解析成對應的struct對象是通過xml.Unmarshal 來完成的,這個過程是如何實現的?可以看到我們的struct定義后面多了一些類似于xml:"serverName" 這樣的內容,這個是struct的一個特性,它們被稱為 struct tag,它們是用來輔助反射的。
package main
import ( "encoding/xml" "fmt" "os" )
type Servers struct { XMLName xml.Name `xml:"servers"` Version string `xml:"version,attr"` Svs []server `xml:"server"` }
type server struct { ServerName string `xml:"serverName"` ServerIP string `xml:"serverIP"` }
func main() { v := &Servers{Version: "1"} v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"}) v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"}) output, err := xml.MarshalIndent(v, " ", " ") if err != nil { fmt.Printf("error: %v\n", err) } os.Stdout.Write([]byte(xml.Header))
os.Stdout.Write(output) }
exec卡住了,阻塞調用肯定卡住了 調用Start
func (*Cmd) Runfunc (c *Cmd) Run() error Run starts the specified command and waits for it to complete. The returned error is nil if the command runs, has no problems copying stdin, stdout, and stderr, and exits with a zero exit status. If the command fails to run or doesn't complete successfully, the error is of type *ExitError. Other error types may be returned for I/O problems. func (*Cmd) Startfunc (c *Cmd) Start() error Start starts the specified command but does not wait for it to complete.
// Description: Golang語法與代碼格式速記 // Author: cxy // Date: 2013-04-01 // Version: 0.3 // TODO 說明
// TODO package
// Go是采用語法解析器自動在每行末尾增加分號,所以在寫代碼的時候可以把分號省略。 // Go編程中只有幾個地方需要手工增加分號,如: for循環使用分號把初始化,條件和遍歷元素分開。在一行中有多條語句時,需要增加分號。 // 不能把控制語句(if, for, switch, or select)、函數、方法 的左大括號單獨放在一行, 如果你這樣作了語法解析器會在大括號之前插入一個分號,導致編譯錯誤。
// 引用包名與導入路徑的最后一個目錄一致
import "fmt" import "math/rand" fmt.Println(rand.Intn(10)) // 0到10之間的非負偽隨機數
// 用圓括號組合導入包,這是“factored”導入語句
import ("fmt"; "math") import ( "fmt" "math" ) // 導入包可以定義別名,防止同名稱的包沖突
import n "net/http" import ( 控制臺 "fmt" m "math" ) 控制臺.Println(m.Pi) // 首字母大寫的名稱是被導出的, 首字母小寫的名稱只能在同一包內訪問(同包跨文件也能訪問)
var In int // In is public
var in byte // in is private
var 看不見 string // 看不見 is private const Com bool = false // Com is public const 還是看不見 uint8 = 1 // 還是看不見 is private
type Integer int // Integer is public
type ブーリアン * bool // ブーリアン is private
func Export() {  } // Export is public
func 導入() {  } // 導入 is private
func (me *Integer) valueOf(s string) int {  } // valueOf is private
func (i ブーリアン) String() string {  } // String is public
// Go 的基本類型:
┌──────┬─────────┬────────┬─────────┬───────────┬────────────┐ │ bool │ string │ │ │ │ │ ├──────┼─────────┼────────┼─────────┼───────────┼────────────┤ │ int │ int8 │ int16 │ int32 │ int64 │ │ │ │ │ │ rune │ │ │ ├──────┼─────────┼────────┼─────────┼───────────┼────────────┤ │ uint │ uint8 │ uint16 │ uint32 │ uint64 │ uintptr │ │ │ byte │ │ │ │ │ ├──────┼─────────┼────────┼─────────┼───────────┼────────────┤ │ │ │ │ float32 │ float64 │ │ ├──────┼─────────┼────────┼─────────┼───────────┼────────────┤ │ │ │ │ │ complex64 │ complex128 │ └──────┴─────────┴────────┴─────────┴───────────┴────────────┘ // byte 是 uint8 的別名 // rune 是 int32 的別名,代表一個Unicode碼點
// 變量聲明, 使用var關鍵字 (Go中只能使用var聲明變量,無需顯式初始化值)
var i int // i = 0
var s string // s = "" (Go中的string不存在nil(null)值,默認零值就是空串 "" 或 ``)
var e error // e = nil, error是Go的內建接口類型,不是基本類型。
// var 語句聲明了一個變量的列表,類型在變量名之后
var a,b,c int // a = 0, b = 0, c = 0
var ( a int // a = 0
b string // b = ""
c uint // c = 0
) // 變量定義時初始化賦值,每個變量對應一個值
var a int = 0 var a,b int = 0, 1 // 初始化使用表達式時,可以省略類型,變量從初始值中獲得類型
var a = 'A' // a int32
c := 1 + 2i // c complex128
var a,b = 0, "B" // a int, b string
a, b := 0, "B" // a int, b string
c := `formatted string` // c string
// := 結構不能使用在函數外,函數外的每個語法塊都必須以關鍵字開始
// 常量可以是字符、字符串、布爾或數字類型的值,數值常量是高精度的值 const x int = 3 const ( a byte = 'A' b string = "B" c bool = true d int = 4 e float32 = 5.1 f complex64 = 6 + 6i ) // 未指定類型的常量由常量值決定其類型 const a = 0 // a int const ( b = 2.3 // b float64
c = true // c bool
) // 自動枚舉常量 iota // iota的枚舉值可以賦值給數值兼容類型 // 每個常量單獨聲明時, iota不會自動遞增(無意義) const a int = iota // a = 0 const b int = iota // b = 0 const c byte = iota // c = 0 const d uint64 = iota // d = 0
// 常量組合聲明時, iota每次引用會逐步自增, 初始值為0,步進值為1 const ( a uint8 = iota // a = 0
b int16 = iota // b = 1
c rune = iota // c = 2
d float64 = iota // d = 3
e uintptr = iota // e = 4
) // 枚舉的常量都為同一類型時, 可以使用簡單序列格式. const ( a = iota // a int32 = 0
b // b int32 = 1
c // c int32 = 2
) // 枚舉序列中的未指定類型的常量會跟隨序列前面最后一次出現類型定義的類型 const ( a byte = iota // a uint8 = 0
b // b uint8 = 1
c // c uint8 = 2
d rune = iota // d int32 = 3
e // e int32 = 4
f // f int32 = 5
) // iota自增值只在一個常量定義組合中有效,跳出常量組合定義后iota值歸0 const ( a = iota // a int32 = 0
b // b int32 = 1
c // c int32 = 2
) const ( e = iota // e int32 = 0 (iota重新初始化并自增)
f // f int32 = 1
) // 定制iota序列初始值與步進值 (通過數學公式實現) const ( a = (iota + 2) * 3 // a int32 = 0 (a=(0+2)*3) 初始值為6,步進值為3
b // b int32 = 3 (b=(1+2)*3)
c // c int32 = 6 (c=(2+2)*3)
d // d int32 = 9 (d=(3+2)*3)
) // 數組聲明帶有長度信息,數組的長度固定
var a [3] int = [3] int{0, 1, 2} // a = [0 1 2]
var b [3] int = [3] int{} // b = [0 0 0]
var c = [3] int{} // c = [0 0 0]
d := [3] int{} // d = [0 0 0]
fmt.Printf("%T\t%#v\t%d\t%d\n", d, d, len(d), cap(d)) // [3]int [3]int{0, 0, 0} 3 3 // 使用 自動計算數組初始數據的長度
var a = [  ] int{0, 1, 2} x := [  ][3] int{{0, 1, 2}, {3, 4, 5}} // slice 指向數組的值,并且同時包含了長度信息
var a [] intfmt.Printf("%T\t%#v\t%d\t%d\n", a, a, len(a), cap(a)) // []int []int(nil) 0 0
var a = new([] int) fmt.Printf("%T\t%#v\t%d\t%d\n", a, a, len(*a), cap(*a)) // *[]int &[]int(nil) 0 0
var b = make([] int, 0) fmt.Printf("%T\t%#v\t%d\t%d\n", b, b, len(b), cap(b)) // []int []int{} 0 0
var c = make([] int, 3, 10) fmt.Printf("%T\t%#v\t%d\t%d\n", c, c, len(c), cap(c)) // []int []int{} 3 10
var d [] int = [] int{0, 1, 2} fmt.Printf("%T\t%#v\t%d\t%d\n", d, d, len(d), cap(d)) // []int []int{0, 1, 2} 3 3
// slice 可以重新切片,創建一個新的 slice 值指向相同的數組
s := [] int{0, 1, 2, 3, 4} fmt.Println(s[1,3]) // [1 2] (截取從開始索引到結束索引-1 之間的片段)
fmt.Println(s[:4]) // [0 1 2 3]
fmt.Println(s[1:]) // [1 2 3 4]
fmt.Println(s[1:1]) // []
// 向slice中添加元素
s := make([] string, 3) s = append(s, "a") // map 在使用之前必須用 make 來創建(不是 new);一個值為 nil 的 map 是空的,并且不能賦值
var m map[ int] intm[0] = 0 // × runtime error: assignment to entry in nil map
fmt.Printf("type: %T\n", m) // map[int]int
fmt.Printf("value: %#v\n", m) // map[int]int(nil)
fmt.Printf("value: %v\n", m) // map[]
fmt.Println("is nil: ", nil == m) // true
fmt.Println("length: ", len(m)) // 0,if m is nil, len(m) is zero.
var m map[ int] int = make(map[ int] int) m[0] = 0 // 插入或修改元素
fmt.Printf("type: %T\n", m) // map[int]int
fmt.Printf("value: %#v\n", m) // map[int]int(0:0)
fmt.Printf("value: %v\n", m) // map[0:0]
fmt.Println("is nil: ", nil == m) // false
fmt.Println("length: ", len(m)) // 1
m = map[ int] int{ 0:0, 1:1, // 最后的逗號是必須的
} m = map[ string]S{ "a":S{0,1}, "b":{2,3}, // 類型名稱可省略
} a := m["a"] // 取值
a, ok := m["a"] // 取值, 并通過ok(bool)判斷key對應的元素是否存在.
delete(m, "a") // 刪除key對應的元素.
// 結構體(struct)就是一個字段的集合, type 定義跟其字面意思相符
type S struct { A int B, c string} type ( A struct { s *S } B struct { A // 組合
} ) // 結構體文法表示通過結構體字段的值作為列表來新分配一個結構體。
var s S = S{0, "1", "2"} // 使用 Name: 語法可以僅列出部分字段。(字段名的順序無關。)
var s S = S{A: 0, B: "1"} var s S = S{} // 特殊的前綴 & 構造了指向結構體文法的指針。
var s *S = &S{0, "1", "2"} // 表達式 new(T) 分配了一個零初始化的 T 值,并返回指向它的指針
var s *S = new(S) // 有指針,但是沒有指針運算,結構體字段使用點號來訪問 // 結構體字段可以通過結構體指針來訪問。通過指針間接的訪問是透明的
fmt.Println(s.A) fmt.Println((*s).A) // TODO interface
type IF interface { a() } // TODO chanel
// TODO error
// if 語句 小括號 ( )是可選的,而 { } 是必須的。 if (i < 0) // 編譯錯誤.
println(i) if i < 0 // 編譯錯誤.
println(i) if (i < 0) { // 編譯通過.
println(i) } if i < 0 { println(i) } else { println(i) } // 可以在條件之前執行一個簡單的語句,由這個語句定義的變量的作用域僅在 if/else 范圍之內 if (i := 0; i < 1) { // 編譯錯誤.
println(i) } if i := 0; (i < 1) { // 編譯通過.
println(i) } if i := 0; i < 0 { // 使用gofmt格式化代碼會自動移除代碼中不必要的小括號( )
println(i) } else if i == 0 { println(i) } else { println(i) } // if語句作用域范圍內定義的變量會覆蓋外部同名變量,(與方法函數內局部變量覆蓋全局變量相同)
a, b := 0, 1 if a, b := 3, 4; a > 1 && b > 2 { println(a, b) // 3 4
} println(a, b) // 0 1
// 只有一種循環結構,for 循環。可以讓前置、后置語句為空,或者全為空 for i := 0; i < 10; i++ {  } for i := 0; i < 10; {  } for ; i < 10; i++ {  } for ; i < 10; {  } for i < 10 {  } for ; ; {  } for {  } // 小括號 ( )是可選的,而 { } 是必須的。 for (i := 0; i < 10; i++) {  } // 編譯錯誤. for i := 0; (i < 10); i++ {  } // 編譯通過. for (i < 10) {  } // 編譯通過.
// TODO continue
// TODO for range
// TODO switch // TODO fallthrough break // TODO type assertion
// TODO select
// TODO goto
// 函數可以沒有參數或接受多個參數
func f() {  } func f(a int) {  } func f(a int, b byte) {  } func f(a int) {  } // 可變參數
func f(a int, b bool, c string) {  } // 函數可以返回任意數量的返回值
func f() int { return 0 } func f() int, string { return 0, "A" } // 函數返回結果參數,可以像變量那樣命名和使用
func f() a int, b string { a = 1 b = "B" return // 或者 return a, b
} // 當兩個或多個連續的函數命名參數是同一類型,則除了最后一個類型之外,其他都可以省略
func f(a,b,c int) {  } func f() a,b,c int {  } func f(a,b,c int) x,y,z int {  } // 函數也是值,可以將函數賦值給變量
var f (func(i int) int) = func(i int) int { return i } fmt.Println(f(3)) // 3
var f func() int = func() int { return 0 } fmt.Println(f()) // 0
var f func() = func() {  } var f = func() {  } f := func() {  } // TODO defer
// TODO 方法
// TODO 內建函數
append cap close complex copy delete imag len make new panic print println real recover // TODO 并發
go func() {  }
寫程序離不了文件操作,這里總結下go語言文件操作。 一、建立與打開 建立文件函數: func Create(name string) (file *File, err Error) func NewFile(fd int, name string) *File 具體見官網:http://golang.org/pkg/os/#Create 打開文件函數: func Open(name string) (file *File, err Error) func OpenFile(name string, flag int, perm uint32) (file *File, err Error) 具體見官網:http://golang.org/pkg/os/#Open 二、寫文件 寫文件函數: func (file *File) Write(b []byte) (n int, err Error) func (file *File) WriteAt(b []byte, off int64) (n int, err Error) func (file *File) WriteString(s string) (ret int, err Error) 具體見官網:http://golang.org/pkg/os/#File.Write 寫文件示例代碼: package main import ( "os" "fmt" ) func main() { userFile := "test.txt" fout,err := os.Create(userFile) defer fout.Close() if err != nil { fmt.Println(userFile,err) return } for i:= 0;i<10;i++ { fout.WriteString("Just a test!\r\n") fout.Write([]byte("Just a test!\r\n")) } } 三、讀文件 讀文件函數: func (file *File) Read(b []byte) (n int, err Error) func (file *File) ReadAt(b []byte, off int64) (n int, err Error) 具體見官網:http://golang.org/pkg/os/#File.Read 讀文件示例代碼: package main import ( "os" "fmt" ) func main() { userFile := "test.txt" fin,err := os.Open(userFile) defer fin.Close() if err != nil { fmt.Println(userFile,err) return } buf := make([]byte, 1024) for{ n, _ := fin.Read(buf) if 0 == n { break } os.Stdout.Write(buf[:n]) } } 四、刪除文件 函數: func Remove(name string) Error
windows下字節序和網絡的相反 func readInt32(conn net.Conn) int32 { num_byte := make([]byte, 4) conn.Read(num_byte) var value int32 = 0 // //windows // byte2 := num_byte[2] // byte3 := num_byte[3] // num_byte[3] = num_byte[0] // num_byte[0] = byte3 // num_byte[2] = num_byte[1] // num_byte[1] = byte2 // //windows
//windows num_byte[0],num_byte[1],num_byte[2],num_byte[3] = num_byte[3],num_byte[2],num_byte[1],num_byte[0]
for i := 0; i < 4; i++ { shift := uint32((4 - 1 - i) * 8) value = value + (int32(num_byte[i])&0x000000FF)<<shift } return value }
golang socket 讀取長數據
1 func read(conn net.Conn, length int) ([]byte, error) {
2 data := make([]byte, length)
3 buf_size := 8
4 buf := make([]byte, buf_size)
5 i := 0
6 for {
7 if length < buf_size {
8 remain := make([]byte, length)
9 _, err := conn.Read(remain)
10 if err != nil {
11 return nil, err
12 }
13 copy(data[i:(i+length)], remain[:])
14 return data, nil
15 } else {
16 _, err := conn.Read(buf)
17 if err != nil {
18 return nil, err
19 }
20 copy(data[i:(i+buf_size)], buf[:])
21 i += buf_size
22 }
23 length -= buf_size
24 }
25 return data, nil
26 }
上面的 _, err := conn.Read(buf) 不能確保讀完,所以修復成下面的代碼func read(conn net.Conn, length int) ([]byte, error) { data := make([]byte, length) buf_size := 1024 buf := make([]byte, buf_size) i := 0 for { if length < buf_size { if length == 0 { return data, nil } remain := make([]byte, length) r, err := conn.Read(remain) if err != nil { return nil, err } copy(data[i:(i+r)], remain[0:r]) i += r length -= r } else { r, err := conn.Read(buf) if err != nil { return nil, err } copy(data[i:(i+r)], buf[0:r]) i += r length -= r }
} return data, nil }
118
119 func (c *conn) Read(b []byte) (int, error) {
120 if !c.ok() {
121 return 0, syscall.EINVAL
122 }
123 return c.fd.Read(b)
124 } b []byte 參數類型 是切片!初始化切片可以通過數組來初始化,也可以通過內置函數make()初始化 .初始化時len=cap,在追加元素時如果容量cap不足時將按len的2倍擴容 查看示例代碼,在線運行示例代碼 s :=[] int {1,2,3 } 直接初始化切片,[]表示是切片類型,{1,2,3}初始化值依次是1,2,3.其cap=len=3s := arr[:] 初始化切片s,是數組arr的引用s := arr[startIndex:endIndex] 將arr中從下標startIndex到endIndex-1 下的元素創建為一個新的切片s := arr[startIndex:] 缺省endIndex時將表示一直到arr的最后一個元素s := arr[:endIndex] 缺省startIndex時將表示從arr的第一個元素開始s1 := s[startIndex:endIndex] 通過切片s初始化切片s1s :=make([]int,len,cap) 通過內置函數make()初始化切片s,[]int 標識為其元素類型為int的切片
恐慌(Panic)和恢復(Recover) Go 沒有像Java 那樣的異常機制,例如你無法像在Java 中那樣拋出一個異常。作為替 代,它使用了恐慌和恢復(panic-and-recover)機制。一定要記得,這應當作為最后的 手段被使用,你的代碼中應當沒有,或者很少的令人恐慌的東西。這是個強大的工具, 明智的使用它。那么,應該如何使用它呢。 下面的描述來自于[7]: Panic 是一個內建函數,可以中斷原有的控制流程,進入一個令人恐慌的流程中。當函 數F 調用panic,函數F 的執行被中斷,并且F 中的延遲函數會正常執行,然 后F 返回到調用它的地方。在調用的地方,F 的行為就像調用了panic。這一過 程繼續向上,直到程序崩潰時的所有goroutine 返回。 恐慌可以直接調用panic 產生。也可以由運行時錯誤產生,例如訪問越界的數 組。 Recover 是一個內建的函數,可以讓進入令人恐慌的流程中的goroutine 恢復過來。recover 僅在延遲函數中有效。 在正常的執行過程中,調用recover 會返回nil 并且沒有其他任何效果。如果 當前的goroutine 陷入恐慌,調用recover 可以捕獲到panic 的輸入值,并且 恢復正常的執行。
摘要: o語言從誕生到普及已經三年了,先行者大都是Web開發的背景,也有了一些普及型的書籍,可系統開發背景的人在學習這些書籍的時候,總有語焉不詳的感覺,網上也有若干流傳甚廣的文章,可其中或多或少總有些與事實不符的技術描述。希望這篇文章能為比較缺少系統編程背景的Web開發人員介紹一下goroutine背后的系統知識。1. 操作系統與運行庫2. 并發與并行 (Concurrency and Paralleli... 閱讀全文
|