2014-06-17 29 views
12

Tôi mới dùng Go và tôi đang cố viết một chương trình nhỏ để lưu các giá trị được liệt kê vào cơ sở dữ liệu. Con đường tôi tuyên bố giá trị của tôi là như sau:Lưu các giá trị được liệt kê vào cơ sở dữ liệu

type FileType int64 
const (
    movie FileType = iota 
    music 
    book 
    etc 
) 

tôi sử dụng những giá trị này trong struct của tôi như thế này:

type File struct { 
    Name  string 
    Type  FileType 
    Size  int64 
} 

tôi sử dụng gorp cho các công cụ cơ sở dữ liệu của tôi, nhưng tôi đoán việc sử dụng gorp không liên quan đến vấn đề của tôi. Tôi đưa công cụ trong DB của tôi như thế này:

dbmap.Insert(&File{"MyBook.pdf",movie,1000}) 

nhưng khi tôi cố gắng lấy lại những thứ ...

dbmap.Select(&dbFiles, "select * from Files") 

tôi nhận được lỗi sau:

panic: reflect.Set: value of type int64 is not assignable to type main.FileType 

Khi tôi sử dụng int64 như nhập cho const(...) và cho trường File.Type, mọi thứ đều hoạt động tốt, nhưng tôi mới sử dụng Go và muốn hiểu sự cố. Cách tôi nhìn thấy, tôi có hai vấn đề:

  1. Tại sao không thể Chuyển đổi công cụ này thành công? Tôi đã xem mã nguồn của các gói phản chiếu và sql của Go và có các phương thức cho loại chuyển đổi này, nhưng chúng dường như không thành công. Đây có phải là một lỗi? Vấn đề là gì?
  2. tôi đã tìm ra, mà người ta có thể thực hiện các giao diện sql.Scanner bằng cách thực hiện các phương pháp sau đây:

    Scan(src interface{}) error 
    

    Tôi cố gắng để thực hiện phương pháp này và tôi thậm chí đã có thể nhận được giá trị ngay từ src và chuyển nó sang a FileType, nhưng tôi đã nhầm lẫn nếu tôi nên thực hiện phương thức cho "(f *FileType) hoặc (f FileType). Dù cách nào phương thức được gọi, tuy nhiên tôi không thể ghi đè f (hoặc ít nhất cập nhật bị mất sau này) và các trường hợp File đã đọc từ DB luôn có giá trị "0" cho File.Type.

Bạn có ý tưởng nào về hai điểm đó không?

Trả lời

24

Gần đây tôi có nhu cầu tương tự, và giải pháp là thực hiện hai giao diện:

  1. sql/driver.Valuer
  2. sql.Scanner

Dưới đây là một ví dụ làm việc:

type FileType int64 

func (u *FileType) Scan(value interface{}) error { *u = FileType(value.(int64)); return nil } 
func (u FileType) Value() (driver.Value, error) { return int64(u), nil } 
+2

Đây là câu trả lời đúng và phải được chấp nhận. Lam tôt lăm. – Darrrrrren

+1

Chỉ cần ra khỏi tò mò, tôi là một tổng số newbie đi. Có một lý do tốt để thực hiện điều này một int64? Có vẻ như bạn chỉ cần một int16 hoặc thậm chí int8, vì bạn có thể sẽ không có hàng tỷ giá trị có thể. – bigblind

+0

@bigblind đó là câu hỏi ban đầu được sử dụng. Tôi thường sẽ không bắt đầu lo lắng quá nhiều về kích thước giá trị cho đến khi nó trở thành một vấn đề, hoặc không gian vấn đề đảm bảo nó. –

0
  1. Đi cần phải cụ thể với các loại, đôi khi có thể gây đau.
  2. (f FileType) rẻ hơn (f *FileType) cho các loại "gốc", khá nhiều trừ khi bạn có loại phức tạp, hầu như không nên sử dụng con trỏ.
  3. Ý của bạn là nó không ghi đè lên nó? bạn đã resave cấu trúc sau khi bạn sửa đổi nó?
+0

liên quan đến 2: ok, nhưng làm thế nào để thay đổi "f" trong trường hợp "(f FileType)" khi tôi viết một cái gì đó như "f = book" trong phương thức Scan, nó không có hiệu lực. – Wolf

+0

Bạn chỉ có thể sửa đổi giá trị của mình, nếu nó hoạt động trên bộ thu con trỏ. Hãy xem xét việc thực hiện 'sql.NullInt64' trong [stdlib] (http://golang.org/src/pkg/database/sql/sql.go?s=2333:2382#L80). – seong

7

Hơi tắt chủ đề, nhưng có thể hữu ích cho người khác khi tôi tiếp tục xem lại câu hỏi/câu trả lời này khi giải quyết một vấn đề tương tự khi làm việc với các trường enum postgres trong golang (được trả về dưới dạng byte).

// Status values 
const ( 
    incomplete Status = "incomplete" 
    complete Status = "complete" 
    reject  Status = "reject" 
) 

type Status string 

func (s *Status) Scan(value interface{}) error { 
    asBytes, ok := value.([]byte) 
    if !ok { 
     return errors.New("Scan source is not []byte") 
    } 
    *s = Status(string(asBytes)) 
    return nil 
} 

func (s SubjectStatus) Value() (driver.Value, error) { 
    // validation would go here 
    return string(s), nil 
} 
+1

Go không có 'enum's. Các hằng số của bạn có kiểu 'string'. Nếu bạn muốn chúng thuộc kiểu 'Status' (bạn làm) thì bạn nên sử dụng' Trạng thái không đầy đủ = "không đầy đủ" ',' Trạng thái hoàn thành = "hoàn thành" ', v.v. (cũng, số nhận dạng tất cả vốn không phải là thành ngữ) . –

+0

@DaveC cảm ơn, đã cập nhật! Chỉ cần được rõ ràng, tôi đề cập đến loại cột 'enum' thực tế của postgres, nhưng sửa chữa tốt. – steevee

Các vấn đề liên quan