github.com/moznion/go-optional@v0.11.1-0.20240312043125-6881072e44c1/README.md (about)

     1  # go-optional [![.github/workflows/check.yml](https://github.com/moznion/go-optional/actions/workflows/check.yml/badge.svg)](https://github.com/moznion/go-optional/actions/workflows/check.yml) [![codecov](https://codecov.io/gh/moznion/go-optional/branch/main/graph/badge.svg?token=0HCVy6COy4)](https://codecov.io/gh/moznion/go-optional) [![GoDoc](https://godoc.org/github.com/moznion/go-optional?status.svg)](https://godoc.org/github.com/moznion/go-optional)
     2  
     3  A library that provides [Go Generics](https://go.dev/blog/generics-proposal) friendly "optional" features.
     4  
     5  ## Synopsis
     6  
     7  ```go
     8  some := optional.Some[int](123)
     9  fmt.Printf("%v\n", some.IsSome()) // => true
    10  fmt.Printf("%v\n", some.IsNone()) // => false
    11  
    12  v, err := some.Take()
    13  fmt.Printf("err is nil: %v\n", err == nil) // => err is nil: true
    14  fmt.Printf("%d\n", v) // => 123
    15  
    16  mapped := optional.Map(some, func (v int) int {
    17      return v * 2
    18  })
    19  fmt.Printf("%v\n", mapped.IsSome()) // => true
    20  
    21  mappedValue, _ := some.Take()
    22  fmt.Printf("%d\n", mappedValue) // => 246
    23  ```
    24  
    25  ```go
    26  none := optional.None[int]()
    27  fmt.Printf("%v\n", none.IsSome()) // => false
    28  fmt.Printf("%v\n", none.IsNone()) // => true
    29  
    30  _, err := none.Take()
    31  fmt.Printf("err is nil: %v\n", err == nil) // => err is nil: false
    32  // the error must be `ErrNoneValueTaken`
    33  
    34  mapped := optional.Map(none, func (v int) int {
    35      return v * 2
    36  })
    37  fmt.Printf("%v\n", mapped.IsNone()) // => true
    38  ```
    39  
    40  and more detailed examples are here: [./examples_test.go](./examples_test.go).
    41  
    42  ## Docs
    43  
    44  [![GoDoc](https://godoc.org/github.com/moznion/go-optional?status.svg)](https://godoc.org/github.com/moznion/go-optional)
    45  
    46  ### Supported Operations
    47  
    48  #### Value Factory Methods
    49  
    50  - [Some[T]\() Option[T]](https://pkg.go.dev/github.com/moznion/go-optional#Some)
    51  - [None[T]\() Option[T]](https://pkg.go.dev/github.com/moznion/go-optional#None)
    52  - [FromNillable[T]\() Option[T]](https://pkg.go.dev/github.com/moznion/go-optional#FromNillable)
    53  - [PtrFromNillable[T]\() Option[T]](https://pkg.go.dev/github.com/moznion/go-optional#PtrFromNillable)
    54  
    55  #### Option value handler methods
    56  
    57  - [Option[T]#IsNone() bool](https://pkg.go.dev/github.com/moznion/go-optional#Option.IsNone)
    58  - [Option[T]#IsSome() bool](https://pkg.go.dev/github.com/moznion/go-optional#Option.IsSome)
    59  - [Option[T]#Unwrap() T](https://pkg.go.dev/github.com/moznion/go-optional#Option.Unwrap)
    60  - [Option[T]#UnwrapAsPtr() \*T](https://pkg.go.dev/github.com/moznion/go-optional#Option.UnwrapAsPtr)
    61  - [Option[T]#Take() (T, error)](https://pkg.go.dev/github.com/moznion/go-optional#Option.Take)
    62  - [Option[T]#TakeOr(fallbackValue T) T](https://pkg.go.dev/github.com/moznion/go-optional#Option.TakeOr)
    63  - [Option[T]#TakeOrElse(fallbackFunc func() T) T](https://pkg.go.dev/github.com/moznion/go-optional#Option.TakeOrElse)
    64  - [Option[T]#Or(fallbackOptionValue Option[T]) Option[T]](https://pkg.go.dev/github.com/moznion/go-optional#Option.Or)
    65  - [Option[T]#OrElse(fallbackOptionFunc func() Option[T]) Option[T]](https://pkg.go.dev/github.com/moznion/go-optional#Option.OrElse)
    66  - [Option[T]#Filter(predicate func(v T) bool) Option[T]](https://pkg.go.dev/github.com/moznion/go-optional#Option.Filter)
    67  - [Option[T]#IfSome(f func(v T))](https://pkg.go.dev/github.com/moznion/go-optional#Option.IfSome)
    68  - [Option[T]#IfSomeWithError(f func(v T) error) error](https://pkg.go.dev/github.com/moznion/go-optional#Option.IfSomeWithError)
    69  - [Option[T]#IfNone(f func())](https://pkg.go.dev/github.com/moznion/go-optional#Option.IfNone)
    70  - [Option[T]#IfNoneWithError(f func() error) error](https://pkg.go.dev/github.com/moznion/go-optional#Option.IfNoneWithError)
    71  - [Option.Map[T, U any](option Option[T], mapper func(v T) U) Option[U]](https://pkg.go.dev/github.com/moznion/go-optional#Map)
    72  - [Option.MapOr[T, U any](option Option[T], fallbackValue U, mapper func(v T) U) U](https://pkg.go.dev/github.com/moznion/go-optional#MapOr)
    73  - [Option.MapWithError[T, U any](option Option[T], mapper func(v T) (U, error)) (Option[U], error)](https://pkg.go.dev/github.com/moznion/go-optional#MapWithError)
    74  - [Option.MapOrWithError[T, U any](option Option[T], fallbackValue U, mapper func(v T) (U, error)) (U, error)](https://pkg.go.dev/github.com/moznion/go-optional#MapOrWithError)
    75  - [Option.FlatMap[T, U any](option Option[T], mapper func(v T) Option[U]) Option[U]](https://pkg.go.dev/github.com/moznion/go-optional#FlatMap)
    76  - [Option.FlatMapOr[T, U any](option Option[T], fallbackValue U, mapper func(v T) Option[U]) U](https://pkg.go.dev/github.com/moznion/go-optional#FlatMapOr)
    77  - [Option.FlatMapWithError[T, U any](option Option[T], mapper func(v T) (Option[U], error)) (Option[U], error)](https://pkg.go.dev/github.com/moznion/go-optional#FlatMapWithError)
    78  - [Option.FlatMapOrWithError[T, U any](option Option[T], fallbackValue U, mapper func(v T) (Option[U], error)) (U, error)](https://pkg.go.dev/github.com/moznion/go-optional#FlatMapOrWithError)
    79  - [Option.Zip[T, U any](opt1 Option[T], opt2 Option[U]) Option[Pair[T, U]]](https://pkg.go.dev/github.com/moznion/go-optional#Zip)
    80  - [Option.ZipWith[T, U, V any](opt1 Option[T], opt2 Option[U], zipper func(opt1 T, opt2 U) V) Option[V]](https://pkg.go.dev/github.com/moznion/go-optional#ZipWith)
    81  - [Option.Unzip[T, U any](zipped Option[Pair[T, U]]) (Option[T], Option[U])](https://pkg.go.dev/github.com/moznion/go-optional#Unzip)
    82  - [Option.UnzipWith[T, U, V any](zipped Option[V], unzipper func(zipped V) (T, U)) (Option[T], Option[U])](https://pkg.go.dev/github.com/moznion/go-optional#UnzipWith)
    83  
    84  ### nil == None[T]
    85  
    86  This library deals with `nil` as same as `None[T]`. So it works with like the following example:
    87  
    88  ```go
    89  var nilValue Option[int] = nil
    90  fmt.Printf("%v\n", nilValue.IsNone()) // => true
    91  fmt.Printf("%v\n", nilValue.IsSome()) // => false
    92  ```
    93  
    94  ### JSON marshal/unmarshal support
    95  
    96  This `Option[T]` type supports JSON marshal and unmarshal.
    97  
    98  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.
    99  
   100  example:
   101  
   102  ```go
   103  type JSONStruct struct {
   104  	Val Option[int] `json:"val"`
   105  }
   106  
   107  some := Some[int](123)
   108  jsonStruct := &JSONStruct{Val: some}
   109  
   110  marshal, err := json.Marshal(jsonStruct)
   111  if err != nil {
   112  	return err
   113  }
   114  fmt.Printf("%s\n", marshal) // => {"val":123}
   115  
   116  var unmarshalJSONStruct JSONStruct
   117  err = json.Unmarshal(marshal, &unmarshalJSONStruct)
   118  if err != nil {
   119  	return err
   120  }
   121  // unmarshalJSONStruct.Val == Some[int](123)
   122  ```
   123  
   124  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]`.
   125  
   126  example:
   127  
   128  ```go
   129  type JSONStruct struct {
   130  	Val Option[int] `json:"val"`
   131  }
   132  
   133  none := None[int]()
   134  jsonStruct := &JSONStruct{Val: none}
   135  
   136  marshal, err := json.Marshal(jsonStruct)
   137  if err != nil {
   138  	return err
   139  }
   140  fmt.Printf("%s\n", marshal) // => {"val":null}
   141  
   142  var unmarshalJSONStruct JSONStruct
   143  err = json.Unmarshal(marshal, &unmarshalJSONStruct)
   144  if err != nil {
   145  	return err
   146  }
   147  // unmarshalJSONStruct.Val == None[int]()
   148  ```
   149  
   150  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.
   151  
   152  ref:
   153  
   154  > 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.
   155  > https://pkg.go.dev/encoding/json#Marshal
   156  
   157  example:
   158  
   159  ```go
   160  type JSONStruct struct {
   161  	OmitemptyVal Option[string] `json:"omitemptyVal,omitempty"` // this should be omitted
   162  }
   163  
   164  jsonStruct := &JSONStruct{OmitemptyVal: None[string]()}
   165  marshal, err := json.Marshal(jsonStruct)
   166  if err != nil {
   167  	return err
   168  }
   169  fmt.Printf("%s\n", marshal) // => {}
   170  ```
   171  
   172  ### SQL Driver Support
   173  
   174  `Option[T]` satisfies [sql/driver.Valuer](https://pkg.go.dev/database/sql/driver#Valuer) and [sql.Scanner](https://pkg.go.dev/database/sql#Scanner), so this type can be used by SQL interface on Golang.
   175  
   176  example of the primitive usage:
   177  
   178  ```go
   179  sqlStmt := "CREATE TABLE tbl (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(32));"
   180  db.Exec(sqlStmt)
   181  
   182  tx, _ := db.Begin()
   183  func() {
   184      stmt, _ := tx.Prepare("INSERT INTO tbl(id, name) values(?, ?)")
   185      defer stmt.Close()
   186      stmt.Exec(1, "foo")
   187  }()
   188  func() {
   189      stmt, _ := tx.Prepare("INSERT INTO tbl(id) values(?)")
   190      defer stmt.Close()
   191      stmt.Exec(2) // name is NULL
   192  }()
   193  tx.Commit()
   194  
   195  var maybeName Option[string]
   196  
   197  row := db.QueryRow("SELECT name FROM tbl WHERE id = 1")
   198  row.Scan(&maybeName)
   199  fmt.Println(maybeName) // Some[foo]
   200  
   201  row := db.QueryRow("SELECT name FROM tbl WHERE id = 2")
   202  row.Scan(&maybeName)
   203  fmt.Println(maybeName) // None[]
   204  ```
   205  
   206  ## Known Issues
   207  
   208  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.
   209  
   210  ## Author
   211  
   212  moznion (<moznion@mail.moznion.net>)
   213