2 回答

TA貢獻(xiàn)1813條經(jīng)驗(yàn) 獲得超2個(gè)贊
請(qǐng)注意,自定義復(fù)合類型不受lib/pq.
如果您想要的只是能夠存儲(chǔ) url,那么最簡(jiǎn)單的方法是driver.Valuer在類型上實(shí)現(xiàn)接口url,然后像使用它一樣使用它pq.Array:
func (u url) Value() (driver.Value, error) {
return fmt.Sprintf("(%s,%d)", u.url, u.status), nil
}
// ...
r, err := db.Exec(update, pq.Array(urls), href)
更多信息可以在這里找到:https ://github.com/lib/pq/issues/544
請(qǐng)注意,我沒(méi)有嘗試使用數(shù)組,僅使用切片,因此您可能必須從使用數(shù)組切換到使用切片,即var urls [1]url使用var urls = make([]url, 1).
如果您還希望能夠從數(shù)據(jù)庫(kù)中檢索 url 數(shù)組,那么您必須實(shí)現(xiàn)sql.Scanner接口,但是這里pq.Array不是很可靠,您必須在切片類型上實(shí)現(xiàn)掃描器并執(zhí)行所有的解析自己。
復(fù)合類型的一般格式是(val1, val2, ...)請(qǐng)注意,您必須在包含逗號(hào)或括號(hào)的值周圍加上雙引號(hào)。例如,要構(gòu)造 url 類型的值,您將使用文字表達(dá)式:(http://example.com,4)。文檔中的更多信息。
復(fù)合類型數(shù)組的格式是{"(val1, val2, ...)" [, ...]},請(qǐng)注意,在這種情況下,如果您需要在需要轉(zhuǎn)義的值周圍加上雙引號(hào)。例如{"(http://example.com,4)","(\"http://example.com/?list=foo,bar,baz\",3)"}
因此,您可以看到復(fù)合類型中的數(shù)據(jù)越復(fù)雜,解析也就越復(fù)雜。
這是一個(gè)粗略的示例(不處理引用值):
type urlslice []url
func (s *urlslice) Scan(src interface{}) error {
var a []byte // the pq array as bytes
switch v := src.(type) {
case []byte:
a = v
case string:
a = []byte(v)
case nil:
*s = nil
return nil
default:
return fmt.Errorf("urlslice.Scan unexpected src type %T", src)
}
a = a[1 : len(a)-1] // drop curly braces
for i := 0; i < len(a); i++ {
if a[i] == '"' && (len(a) > (i+1) && a[i+1] == '(') { // element start?
i += 2 // move past `"(`
j := i // start of url.url
u := url{}
for ; i < len(a) && a[i] != ','; i++ {
}
u.url = string(a[j:i])
i += 1 // move past `,`
j = i // start of url.status
for ; i < len(a) && a[i] != ')'; i++ {
}
i64, err := strconv.ParseInt(string(a[j:i]), 10, 64)
if err != nil {
return err
}
u.status = int(i64)
*s = append(*s, u)
i += 2 // move past `)",`
}
}
return nil
}
為了完整起見(jiàn),這里是切片類型實(shí)現(xiàn)的 Valuer 接口,同樣沒(méi)有處理可能需要它的值的正確引用:
func (s urlslice) Value() (driver.Value, error) {
data := []byte{'{'}
for _, url := range s {
data = append(data, '"', '(')
data = append(data, []byte(url.url)...)
data = append(data, ',')
data = strconv.AppendInt(data, int64(url.status), 10)
data = append(data, ')', '"', ',')
}
data[len(data)-1] = '}' // replace last ',' with '}' to close the array
return data, nil
}
通過(guò)urlslice直接實(shí)現(xiàn)這兩個(gè)接口,您可以停止使用pq.Array.
var urls = urlslice{{
url: "http://example.com",
status: 4,
}}
update := `UPDATE "public"."tiantang_page" SET "urls"=$1 where "href"=$2`
r, err := db.Exec(update, urls, href)
if err != nil {
log.Fatal(err)
}
var urls2 urlslice
selurls := `SELECT "urls" FROM "public"."tiantang_page" where "href" = $1`
if err := db.QueryRow(selurls, href).Scan(&urls2); err != nil {
log.Fatal(err)
}
請(qǐng)記住,以上兩個(gè)示例都應(yīng)僅被視為解決此問(wèn)題的方向的提示。這兩個(gè)示例不僅不完整,因?yàn)樗鼈儾惶幚硪弥担宜鼈円膊皇欠浅?yōu)雅的實(shí)現(xiàn)。

TA貢獻(xiàn)2003條經(jīng)驗(yàn) 獲得超2個(gè)贊
相當(dāng)完整的復(fù)合文字解析器:
type parseState int
const (
state_initial parseState = iota // start
state_value_start // no bytes read from value yet
state_value // unquoted value
state_quoted // inside quote
state_value_end // after a close quote
state_end // after close paren
)
func parseComposite(in []byte) ([]string, error) {
state := state_initial
ret := []string{}
val := []byte{}
for _, b := range in {
switch state {
case state_initial:
if b != '(' {
return nil, fmt.Errorf("initial character not ')': %v", in)
} else {
state = state_value_start
}
case state_value_start:
if b == '"' {
state = state_quoted
continue
}
fallthrough
case state_value:
if b == ',' {
ret = append(ret, string(val))
val = nil
state = state_value_start
} else if b == ')' {
ret = append(ret, string(val))
val = nil
state = state_end
} else {
val = append(val, b)
}
case state_quoted:
if b == '"' {
ret = append(ret, string(val))
val = nil
state = state_value_end
} else {
val = append(val, b)
}
case state_value_end:
if b == ',' {
state = state_value_start
} else if b == ')' {
state = state_end
} else {
return nil, fmt.Errorf("invalid delimiter after closing quote: %v", in)
}
case state_end:
return nil, fmt.Errorf("trailing bytes: %v", in)
}
}
if state != state_end {
return nil, fmt.Errorf("unterminated value: %v", in)
}
return ret, nil
}
- 2 回答
- 0 關(guān)注
- 143 瀏覽
添加回答
舉報(bào)