|
xml對應(yīng)的struct 屬性必須大寫,否則無法實現(xiàn)!
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文件解析成對應(yīng)的struct對象是通過xml.Unmarshal 來完成的,這個過程是如何實現(xiàn)的?可以看到我們的struct定義后面多了一些類似于xml:"serverName" 這樣的內(nèi)容,這個是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卡住了,阻塞調(diào)用肯定卡住了 調(diào)用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循環(huán)使用分號把初始化,條件和遍歷元素分開。在一行中有多條語句時,需要增加分號。 // 不能把控制語句(if, for, switch, or select)、函數(shù)、方法 的左大括號單獨放在一行, 如果你這樣作了語法解析器會在大括號之前插入一個分號,導(dǎo)致編譯錯誤。
// 引用包名與導(dǎo)入路徑的最后一個目錄一致
import "fmt" import "math/rand" fmt.Println(rand.Intn(10)) // 0到10之間的非負偽隨機數(shù)
// 用圓括號組合導(dǎo)入包,這是“factored”導(dǎo)入語句
import ("fmt"; "math") import ( "fmt" "math" ) // 導(dǎo)入包可以定義別名,防止同名稱的包沖突
import n "net/http" import ( 控制臺 "fmt" m "math" ) 控制臺.Println(m.Pi) // 首字母大寫的名稱是被導(dǎo)出的, 首字母小寫的名稱只能在同一包內(nèi)訪問(同包跨文件也能訪問)
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 導(dǎo)入() {  } // 導(dǎo)入 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關(guān)鍵字 (Go中只能使用var聲明變量,無需顯式初始化值)
var i int // i = 0
var s string // s = "" (Go中的string不存在nil(null)值,默認零值就是空串 "" 或 ``)
var e error // e = nil, error是Go的內(nèi)建接口類型,不是基本類型。
// var 語句聲明了一個變量的列表,類型在變量名之后
var a,b,c int // a = 0, b = 0, c = 0
var ( a int // a = 0
b string // b = ""
c uint // c = 0
) // 變量定義時初始化賦值,每個變量對應(yīng)一個值
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
// := 結(jié)構(gòu)不能使用在函數(shù)外,函數(shù)外的每個語法塊都必須以關(guān)鍵字開始
// 常量可以是字符、字符串、布爾或數(shù)字類型的值,數(shù)值常量是高精度的值 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的枚舉值可以賦值給數(shù)值兼容類型 // 每個常量單獨聲明時, 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
) // 枚舉序列中的未指定類型的常量會跟隨序列前面最后一次出現(xiàn)類型定義的類型 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序列初始值與步進值 (通過數(shù)學(xué)公式實現(xiàn)) 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)
) // 數(shù)組聲明帶有長度信息,數(shù)組的長度固定
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 // 使用 自動計算數(shù)組初始數(shù)據(jù)的長度
var a = [  ] int{0, 1, 2} x := [  ][3] int{{0, 1, 2}, {3, 4, 5}} // slice 指向數(shù)組的值,并且同時包含了長度信息
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 可以重新切片,創(chuàng)建一個新的 slice 值指向相同的數(shù)組
s := [] int{0, 1, 2, 3, 4} fmt.Println(s[1,3]) // [1 2] (截取從開始索引到結(jié)束索引-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 來創(chuàng)建(不是 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對應(yīng)的元素是否存在.
delete(m, "a") // 刪除key對應(yīng)的元素.
// 結(jié)構(gòu)體(struct)就是一個字段的集合, type 定義跟其字面意思相符
type S struct { A int B, c string} type ( A struct { s *S } B struct { A // 組合
} ) // 結(jié)構(gòu)體文法表示通過結(jié)構(gòu)體字段的值作為列表來新分配一個結(jié)構(gòu)體。
var s S = S{0, "1", "2"} // 使用 Name: 語法可以僅列出部分字段。(字段名的順序無關(guān)。)
var s S = S{A: 0, B: "1"} var s S = S{} // 特殊的前綴 & 構(gòu)造了指向結(jié)構(gòu)體文法的指針。
var s *S = &S{0, "1", "2"} // 表達式 new(T) 分配了一個零初始化的 T 值,并返回指向它的指針
var s *S = new(S) // 有指針,但是沒有指針運算,結(jié)構(gòu)體字段使用點號來訪問 // 結(jié)構(gòu)體字段可以通過結(jié)構(gòu)體指針來訪問。通過指針間接的訪問是透明的
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) } // 可以在條件之前執(zhí)行一個簡單的語句,由這個語句定義的變量的作用域僅在 if/else 范圍之內(nèi) 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語句作用域范圍內(nèi)定義的變量會覆蓋外部同名變量,(與方法函數(shù)內(nèi)局部變量覆蓋全局變量相同)
a, b := 0, 1 if a, b := 3, 4; a > 1 && b > 2 { println(a, b) // 3 4
} println(a, b) // 0 1
// 只有一種循環(huán)結(jié)構(gòu),for 循環(huán)??梢宰屒爸?、后置語句為空,或者全為空 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
// 函數(shù)可以沒有參數(shù)或接受多個參數(shù)
func f() {  } func f(a int) {  } func f(a int, b byte) {  } func f(a int) {  } // 可變參數(shù)
func f(a int, b bool, c string) {  } // 函數(shù)可以返回任意數(shù)量的返回值
func f() int { return 0 } func f() int, string { return 0, "A" } // 函數(shù)返回結(jié)果參數(shù),可以像變量那樣命名和使用
func f() a int, b string { a = 1 b = "B" return // 或者 return a, b
} // 當(dāng)兩個或多個連續(xù)的函數(shù)命名參數(shù)是同一類型,則除了最后一個類型之外,其他都可以省略
func f(a,b,c int) {  } func f() a,b,c int {  } func f(a,b,c int) x,y,z int {  } // 函數(shù)也是值,可以將函數(shù)賦值給變量
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 內(nèi)建函數(shù)
append cap close complex copy delete imag len make new panic print println real recover // TODO 并發(fā)
go func() {  }
寫程序離不了文件操作,這里總結(jié)下go語言文件操作。 一、建立與打開 建立文件函數(shù): func Create(name string) (file *File, err Error) func NewFile(fd int, name string) *File 具體見官網(wǎng):http://golang.org/pkg/os/#Create 打開文件函數(shù): func Open(name string) (file *File, err Error) func OpenFile(name string, flag int, perm uint32) (file *File, err Error) 具體見官網(wǎng):http://golang.org/pkg/os/#Open 二、寫文件 寫文件函數(shù): 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) 具體見官網(wǎng):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")) } } 三、讀文件 讀文件函數(shù): func (file *File) Read(b []byte) (n int, err Error) func (file *File) ReadAt(b []byte, off int64) (n int, err Error) 具體見官網(wǎng):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]) } } 四、刪除文件 函數(shù): func Remove(name string) Error
windows下字節(jié)序和網(wǎng)絡(luò)的相反 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 讀取長數(shù)據(jù)
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) 不能確保讀完,所以修復(fù)成下面的代碼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 參數(shù)類型 是切片!初始化切片可以通過數(shù)組來初始化,也可以通過內(nèi)置函數(shù)make()初始化 .初始化時len=cap,在追加元素時如果容量cap不足時將按len的2倍擴容 查看示例代碼,在線運行示例代碼 s :=[] int {1,2,3 } 直接初始化切片,[]表示是切片類型,{1,2,3}初始化值依次是1,2,3.其cap=len=3s := arr[:] 初始化切片s,是數(shù)組arr的引用s := arr[startIndex:endIndex] 將arr中從下標(biāo)startIndex到endIndex-1 下的元素創(chuàng)建為一個新的切片s := arr[startIndex:] 缺省endIndex時將表示一直到arr的最后一個元素s := arr[:endIndex] 缺省startIndex時將表示從arr的第一個元素開始s1 := s[startIndex:endIndex] 通過切片s初始化切片s1s :=make([]int,len,cap) 通過內(nèi)置函數(shù)make()初始化切片s,[]int 標(biāo)識為其元素類型為int的切片
恐慌(Panic)和恢復(fù)(Recover) Go 沒有像Java 那樣的異常機制,例如你無法像在Java 中那樣拋出一個異常。作為替 代,它使用了恐慌和恢復(fù)(panic-and-recover)機制。一定要記得,這應(yīng)當(dāng)作為最后的 手段被使用,你的代碼中應(yīng)當(dāng)沒有,或者很少的令人恐慌的東西。這是個強大的工具, 明智的使用它。那么,應(yīng)該如何使用它呢。 下面的描述來自于[7]: Panic 是一個內(nèi)建函數(shù),可以中斷原有的控制流程,進入一個令人恐慌的流程中。當(dāng)函 數(shù)F 調(diào)用panic,函數(shù)F 的執(zhí)行被中斷,并且F 中的延遲函數(shù)會正常執(zhí)行,然 后F 返回到調(diào)用它的地方。在調(diào)用的地方,F(xiàn) 的行為就像調(diào)用了panic。這一過 程繼續(xù)向上,直到程序崩潰時的所有g(shù)oroutine 返回。 恐慌可以直接調(diào)用panic 產(chǎn)生。也可以由運行時錯誤產(chǎn)生,例如訪問越界的數(shù) 組。 Recover 是一個內(nèi)建的函數(shù),可以讓進入令人恐慌的流程中的goroutine 恢復(fù)過來。recover 僅在延遲函數(shù)中有效。 在正常的執(zhí)行過程中,調(diào)用recover 會返回nil 并且沒有其他任何效果。如果 當(dāng)前的goroutine 陷入恐慌,調(diào)用recover 可以捕獲到panic 的輸入值,并且 恢復(fù)正常的執(zhí)行。
摘要: o語言從誕生到普及已經(jīng)三年了,先行者大都是Web開發(fā)的背景,也有了一些普及型的書籍,可系統(tǒng)開發(fā)背景的人在學(xué)習(xí)這些書籍的時候,總有語焉不詳?shù)母杏X,網(wǎng)上也有若干流傳甚廣的文章,可其中或多或少總有些與事實不符的技術(shù)描述。希望這篇文章能為比較缺少系統(tǒng)編程背景的Web開發(fā)人員介紹一下goroutine背后的系統(tǒng)知識。1. 操作系統(tǒng)與運行庫2. 并發(fā)與并行 (Concurrency and Paralleli... 閱讀全文
|