2014-01-16 96 views
8

如果有人正在使用數據庫,Null*類型對於大多數場景非常有用,因爲通常不需要「零」值,NOT NULL約束等並提醒你,你沒有通過所有必要的數據。golang有效地使用Null *類型

所以你創建了一個結構如下:

type Role struct { 
    Id sql.NullInt64 
    Code sql.NullString 
} 

那是偉大的,但現在你不能得到屬性的直接訪問,並必須使用Role.Id.Value到get和set,這是會得到相當當你每次想要訪問這些屬性時都必須有額外的步驟時,才能在一個大型應用程序中使用它。

這將是很好,如果你可以直接分配例如。 Role.Code = "Fsfs",並且當您對空檢查感興趣時,能夠執行諸如Role.Code.IsNull之類的操作。這樣的事情可能嗎?

+0

如果你不介意使用它們,指針的零值爲零 - 'type Role {Code * string}' – codepushr

回答

1

正在使用中間指針值(s)選項嗎?如果你改變r的值

fmt.Println(r.Code, r.Code.Valid) 

package main 

import "fmt" 

type tmp struct { 
    Value int 
} 

func getInt() *int { 
    i := 123 

    return &i 
} 

func main() { 
    // Re 
    var v *int 

    v = nil 

    fmt.Printf("%T/%v\n", v, v) 

    if v == nil { 
     println("nil...") 
    } 

    v = getInt() 

    fmt.Printf("%T/%v\n", v, *v) 

    if v != nil { 
     println("not nil...") 
    } 

    s := tmp{*v} 

    fmt.Printf("%T/%v\n", s, s) 
} 

http://play.golang.org/p/lBrwTKh6-v

1

您可以像訪問Role.Code:

var r *Role 
r.Code = *code 

您可以檢查null這樣。手動編碼,無需使用sql.Scanner一個安裝程序可能會有所幫助:

func (r *Role) SetCode(code string) { 
    r.Code.String = code 
    r.Code.Valid = true 
} 
func main() { 
var r *Role 
r.SetCode("mi") 
if r.Code.Valid { 
    fmt.Println(r.Code) 
} 

我想這一點在這裏:https://play.golang.org/p/faxQUm-2lr

1

Keep應用和數據庫代碼獨立

// Role belongs to app code, no compromises. 

type Role struct { 
    Id int64 
    Code string 
} 

建模數據庫。

// Database has tables with columns. 

type Table struct { 
    Name string 
    Columns []string 
} 

var RoleTable = Table{ 
    Name: "roles", 
    Columns: []string{ 
     "id", 
     "code", 
    }, 
} 

編寫一次代碼在模型和數據庫行之間進行轉換。

// Database package needs to make it work. 

// Write a model to database row. 
type Writer struct { 
    Role 
} 

func (w *Writer) Write() []interface{} { 
    return []interface{}{ 
     w.Role.Id, 
     sql.NullString{ 
      Valid: len(w.Role.Code) > 0, 
      String: w.Role.String, 
     }, 
    } 
} 

// Read a database row into model. 
type Reader struct { 
    Id int64 
    Code sql.NullString 
} 

func (r *Reader) Scan(row *sql.Row) error { 
    return row.Scan(
     &r.Id, 
     &r.Code, 
    ) 
} 

func (r *Reader) Read() Role { 
    return Role{ 
     Id: r.Id, 
     Code: r.Code.String, 
    } 
} 

您的模式與應用模型分離。在保存或加載時,可以將結構壓平,如用戶聯繫人詳細信息。

// Nested struct in app code. 
type User struct { 
    TwitterProfile struct { 
     Id string 
     ScreenName string 
    } 
} 

// Database row is normalized flat. 
var UserTable = Table{ 
    Name: "users", 
    Columns: []string{ 
     "twitter_id", 
     "twitter_screen_name", 
    }, 
} 

它很靈活。您甚至可以在沒有中間結構的情況下掃描連接行。

type RowMux struct { 
    vs []interface{} 
} 

func (mux *RowMux) Scan(vs ...interface{}) error { 
    mux.vs = append(mux.vs, vs...) 
    return nil 
} 

func (mux *RowMux) Mux(row *sql.Row) error { 
    return row.Scan(mux.vs...) 
} 

// Scan join rows! 
row := db.QueryRow(` 
    SELECT users.*, roles.* 
    FROM users 
    JOIN roles ON users.id = roles.user_id 
    WHERE users.twitter_id = "123" 
`) 
mux := &RowMux{} 
userReader := &UserReader{} 
userReader.Scan(mux) 
roleReader := &RoleReader{} 
roleReader.Scan(mux) 
if err := mux.Mux(row); err != nil { 
    panic(err) 
} 
user := userReader.Read() 
role := roleReader.Read()