A library that provides Go Generics friendly "optional" features.
some := optional.Some[int](123)
fmt.Printf("%v\n", some.IsSome()) // => true
fmt.Printf("%v\n", some.IsNone()) // => false
v, err := some.Take()
fmt.Printf("err is nil: %v\n", err == nil) // => err is nil: true
fmt.Printf("%d\n", v) // => 123
mapped := optional.Map(some, func (v int) int {
return v * 2
})
fmt.Printf("%v\n", mapped.IsSome()) // => true
mappedValue, _ := some.Take()
fmt.Printf("%d\n", mappedValue) // => 246
none := optional.None[int]()
fmt.Printf("%v\n", none.IsSome()) // => false
fmt.Printf("%v\n", none.IsNone()) // => true
_, err := none.Take()
fmt.Printf("err is nil: %v\n", err == nil) // => err is nil: false
// the error must be `ErrNoneValueTaken`
mapped := optional.Map(none, func (v int) int {
return v * 2
})
fmt.Printf("%v\n", mapped.IsNone()) // => true
and more detailed examples are here: ./examples_test.go.
This library deals with nil
as same as None[T]
. So it works with like the following example:
var nilValue Option[int] = nil
fmt.Printf("%v\n", nilValue.IsNone()) // => true
fmt.Printf("%v\n", nilValue.IsSome()) // => false
This Option[T]
type supports JSON marshal and unmarshal.
If the value wanted to marshal is Some[T]
then it marshals that value into the JSON bytes simply, and in unmarshaling, if the given JSON string/bytes has the actual value on corresponded property, it unmarshals that value into Some[T]
value.
example:
type JSONStruct struct {
Val Option[int] `json:"val"`
}
some := Some[int](123)
jsonStruct := &JSONStruct{Val: some}
marshal, err := json.Marshal(jsonStruct)
if err != nil {
return err
}
fmt.Printf("%s\n", marshal) // => {"val":123}
var unmarshalJSONStruct JSONStruct
err = json.Unmarshal(marshal, &unmarshalJSONStruct)
if err != nil {
return err
}
// unmarshalJSONStruct.Val == Some[int](123)
Elsewise, when the value is None[T]
, the marshaller serializes that value as null
. And if the unmarshaller gets the JSON null
value on a property corresponding to the Optional[T]
value, or the value of a property is missing, that deserializes that value as None[T]
.
example:
type JSONStruct struct {
Val Option[int] `json:"val"`
}
none := None[int]()
jsonStruct := &JSONStruct{Val: none}
marshal, err := json.Marshal(jsonStruct)
if err != nil {
return err
}
fmt.Printf("%s\n", marshal) // => {"val":null}
var unmarshalJSONStruct JSONStruct
err = json.Unmarshal(marshal, &unmarshalJSONStruct)
if err != nil {
return err
}
// unmarshalJSONStruct.Val == None[int]()
And this also supports omitempty
option for JSON unmarshaling. If the value of the property is None[T]
and that property has omitempty
option, it omits that property.
ref:
The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string. https://pkg.go.dev/encoding/json#Marshal
example:
type JSONStruct struct {
OmitemptyVal Option[string] `json:"omitemptyVal,omitempty"` // this should be omitted
}
jsonStruct := &JSONStruct{OmitemptyVal: None[string]()}
marshal, err := json.Marshal(jsonStruct)
if err != nil {
return err
}
fmt.Printf("%s\n", marshal) // => {}
Option[T]
satisfies sql/driver.Valuer and sql.Scanner, so this type can be used by SQL interface on Golang.
example of the primitive usage:
sqlStmt := "CREATE TABLE tbl (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(32));"
db.Exec(sqlStmt)
tx, _ := db.Begin()
func() {
stmt, _ := tx.Prepare("INSERT INTO tbl(id, name) values(?, ?)")
defer stmt.Close()
stmt.Exec(1, "foo")
}()
func() {
stmt, _ := tx.Prepare("INSERT INTO tbl(id) values(?)")
defer stmt.Close()
stmt.Exec(2) // name is NULL
}()
tx.Commit()
var maybeName Option[string]
row := db.QueryRow("SELECT name FROM tbl WHERE id = 1")
row.Scan(&maybeName)
fmt.Println(maybeName) // Some[foo]
row := db.QueryRow("SELECT name FROM tbl WHERE id = 2")
row.Scan(&maybeName)
fmt.Println(maybeName) // None[]
The runtime raises a compile error like "methods cannot have type parameters", so Map()
, MapOr()
, MapWithError()
, MapOrWithError()
, Zip()
, ZipWith()
, Unzip()
and UnzipWith()
have been providing as functions. Basically, it would be better to provide them as the methods, but currently, it compromises with the limitation.
moznion ([email protected])