package reflect
import "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
Package reflect extends the standard reflect package.
Index ¶
- func DoEqual(x, y any) (err error)
- func IsEqual(x, y any) bool
- func IsNil(v any) bool
- func Marshal(obj any) (out []byte, err error)
- func Set(obj reflect.Value, val string) (err error)
- func Tag(field reflect.StructField, tag string) (val string, opts []string, hasTag bool)
- func Unmarshal(obj reflect.Value, val []byte) (ok bool, err error)
- type Equaler
Examples ¶
- DoEqual (Struct)
- Equaler
- IsEqual (Struct)
- IsNil
- Marshal
- Set (Bool)
- Set (Float)
- Set (Int)
- Set (SliceByte)
- Set (SliceString)
- Set (Unmarshal)
- Tag
- Unmarshal (UnmarshalBinary)
- Unmarshal (UnmarshalJSON)
- Unmarshal (UnmarshalText)
Functions ¶
func DoEqual ¶
DoEqual is a naive interfaces comparison for two values.
If the type is a struct and implement Equaler interface it will use the
[Equal] method in that struct to compare the values.
A struct's field tagged with `noequal:""` will be skipped from being
processed.
Code:play
Output:Example (Struct)¶
package main
import (
"fmt"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
func main() {
type T struct {
vstring string
vnoequal string `noequal:""` // This field will not checked for equality.
}
var (
t1 = &T{
vstring: `a string`,
vnoequal: `skip`,
}
t2 = &T{
vstring: `a string`,
vnoequal: `skipped too`,
}
)
fmt.Println(libreflect.DoEqual(t1, t2))
}
<nil>
func IsEqual ¶
IsEqual is a naive interfaces comparison for two values.
If the type is a struct and implement Equaler interface it will use the
[Equal] method in that struct to compare the values.
A struct's field tagged with `noequal:""` will be skipped from being
processed.
Code:play
Output:Example (Struct)¶
package main
import (
"fmt"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
func main() {
type T struct {
vstring string
vnoequal string `noequal:""` // This field will not checked for equality.
}
var (
t1 = &T{
vstring: `a string`,
vnoequal: `skip`,
}
t2 = &T{
vstring: `a string`,
vnoequal: `skipped too`,
}
)
fmt.Println(libreflect.IsEqual(t1, t2))
}
true
func IsNil ¶
IsNil will return true if v's type is chan, func, interface, map, pointer,
or slice and its value is `nil`; otherwise it will return false.
Code:play
Output:Example¶
package main
import (
"errors"
"fmt"
"net/http"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
type F func()
type T struct{}
func (t *T) J() bool {
return true
}
func main() {
var (
aBoolean bool
aChannel chan int
aFunction F
aMap map[int]int
aPtr *T
aSlice []int
anInt int
emptyError error
fs http.FileSystem
)
cases := []struct {
v any
}{
{}, // Uninitialized any.
{v: aBoolean},
{v: aChannel}, // Uninitialized channel.
{v: aFunction}, // Empty func type.
{v: aMap}, // Uninitialized map.
{v: make(map[int]int)}, // Initialized map.
{v: aPtr}, // Uninitialized pointer to struct.
{v: &T{}}, // Initialized pointer to struct.
{v: aSlice}, // Uninitialized slice.
{v: make([]int, 0)}, // Initialized slice.
{v: anInt},
{v: emptyError},
{v: errors.New("e")}, // Initialized error.
{v: fs}, // Uninitialized interface type to any.
}
for _, c := range cases {
fmt.Printf("%19T: v == nil is %5t, IsNil() is %5t\n", c.v, c.v == nil, libreflect.IsNil(c.v))
}
}
<nil>: v == nil is true, IsNil() is true
bool: v == nil is false, IsNil() is false
chan int: v == nil is false, IsNil() is true
reflect_test.F: v == nil is false, IsNil() is true
map[int]int: v == nil is false, IsNil() is true
map[int]int: v == nil is false, IsNil() is false
*reflect_test.T: v == nil is false, IsNil() is true
*reflect_test.T: v == nil is false, IsNil() is false
[]int: v == nil is false, IsNil() is true
[]int: v == nil is false, IsNil() is false
int: v == nil is false, IsNil() is false
<nil>: v == nil is true, IsNil() is true
*errors.errorString: v == nil is false, IsNil() is false
<nil>: v == nil is true, IsNil() is true
func Marshal ¶
Marshal marshal the obj value to []byte by calling one of the method: MarshalBinary, MarshalJSON, or MarshalText; in respective order.
If obj implement one of the method with valid signature, it will return the marshaled bytes.
If the method signature invalid it will return an error.
If obj is nil or none of the method exist it will return nil without an
error.
Code:play
Output:Example¶
package main
import (
"errors"
"fmt"
"math/big"
"net/url"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
type InvalidMarshalText struct{}
func (imt *InvalidMarshalText) MarshalText() (string, error) {
return "", nil
}
type ErrorMarshalJSON struct{}
func (emj *ErrorMarshalJSON) MarshalJSON() ([]byte, error) {
return nil, errors.New(`ErrorMarshalJSON: test`)
}
func main() {
var (
vint = 1
vURL, _ = url.Parse("https://example.org")
bigRat = big.NewRat(100, 2)
bigInt = big.NewInt(50)
imt = &InvalidMarshalText{}
emj = &ErrorMarshalJSON{}
out []byte
err error
)
out, err = libreflect.Marshal(vint)
fmt.Println(out, err)
out, err = libreflect.Marshal(&vint)
fmt.Println(out, err)
out, err = libreflect.Marshal(vURL)
fmt.Println(string(out), err)
out, err = libreflect.Marshal(bigRat)
fmt.Println(string(out), err)
out, err = libreflect.Marshal(bigInt)
fmt.Println(string(out), err)
out, err = libreflect.Marshal(imt)
fmt.Println(string(out), err)
out, err = libreflect.Marshal(emj)
fmt.Println(string(out), err)
}
[] <nil>
[] <nil>
https://example.org <nil>
50 <nil>
50 <nil>
Marshal: expecting first return as []byte got string
Marshal: ErrorMarshalJSON: test
func Set ¶
Set the obj value by converting the string val to the obj type.
If the obj type is an interface or struct, its value will be set by calling Unmarshal function.
It will return an error if,
- obj is not setable, variable is passed without pointer or pointer not initialized.
- val is overflow
- obj Kind is Invalid, Array, Chan, Func, Map, or UnsafePointer.
Example (Bool)¶
Code:play
package main import ( "fmt" "reflect" libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect" ) func main() { type Bool bool var ( err error vbool bool mybool Bool ) err = libreflect.Set(reflect.ValueOf(&vbool), "YES") if err != nil { fmt.Println("error:", err) } else { fmt.Println("YES:", vbool) } err = libreflect.Set(reflect.ValueOf(&vbool), "TRUE") if err != nil { fmt.Println("error:", err) } else { fmt.Println("TRUE:", vbool) } err = libreflect.Set(reflect.ValueOf(&vbool), "False") if err != nil { fmt.Println("error:", err) } else { fmt.Println("False:", vbool) } err = libreflect.Set(reflect.ValueOf(&vbool), "1") if err != nil { fmt.Println("error:", err) } else { fmt.Println("1:", vbool) } err = libreflect.Set(reflect.ValueOf(&mybool), "true") if err != nil { fmt.Println("error:", err) } else { fmt.Println("true:", mybool) } }
Output:
YES: true TRUE: true False: false 1: true true: true
Example (Float)¶
Code:play
package main import ( "fmt" "reflect" libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect" ) func main() { type myFloat float32 var ( vf32 float32 myfloat myFloat err error ) err = libreflect.Set(reflect.ValueOf(&vf32), "1.223") if err != nil { fmt.Println("error:", err) } else { fmt.Println(vf32) } err = libreflect.Set(reflect.ValueOf(&myfloat), "999.999") if err != nil { fmt.Println("error:", err) } else { fmt.Println(myfloat) } }
Output:
1.223 999.999
Example (Int)¶
Code:play
package main
import (
"fmt"
"reflect"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
func main() {
type myInt int
var (
vint int
vint8 int8
vint16 int16
vmyint myInt
err error
)
err = libreflect.Set(reflect.ValueOf(&vint), "")
if err != nil {
fmt.Println("error:", err)
} else {
fmt.Println(vint)
}
err = libreflect.Set(reflect.ValueOf(&vint), "1")
if err != nil {
fmt.Println("error:", err)
} else {
fmt.Println(vint)
}
err = libreflect.Set(reflect.ValueOf(&vint8), "-128")
if err != nil {
fmt.Println("error:", err)
} else {
fmt.Println(vint8)
}
// Value of int16 is overflow.
err = libreflect.Set(reflect.ValueOf(&vint16), "32768")
if err != nil {
fmt.Println("error:", err)
} else {
fmt.Println(vint16)
}
err = libreflect.Set(reflect.ValueOf(&vmyint), "32768")
if err != nil {
fmt.Println("error:", err)
} else {
fmt.Println(vmyint)
}
}
Output:
0 1 -128 error: Set: int16 value is overflow: 32768 32768
Example (SliceByte)¶
Code:play
package main import ( "fmt" "reflect" libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect" ) func main() { type myBytes []byte var ( vbytes []byte vmyBytes myBytes err error ) err = libreflect.Set(reflect.ValueOf(vbytes), "Show me") if err != nil { fmt.Println("error:", err) } else { fmt.Println(string(vbytes)) } err = libreflect.Set(reflect.ValueOf(&vbytes), "a hero") if err != nil { fmt.Println("error:", err) } else { fmt.Println(string(vbytes)) } err = libreflect.Set(reflect.ValueOf(&vbytes), "") if err != nil { fmt.Println("error:", err) } else { fmt.Println(string(vbytes)) } err = libreflect.Set(reflect.ValueOf(&vmyBytes), "and I will write you a tragedy") if err != nil { fmt.Println("error:", err) } else { fmt.Println(string(vmyBytes)) } }
Output:
error: Set: object []uint8 is not setable a hero and I will write you a tragedy
Example (SliceString)¶
Code:play
package main import ( "fmt" "reflect" libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect" ) func main() { var ( vstring []string err error ) err = libreflect.Set(reflect.ValueOf(vstring), "Show me") if err != nil { fmt.Println("error:", err) } else { fmt.Println(vstring) } err = libreflect.Set(reflect.ValueOf(&vstring), "a hero") if err != nil { fmt.Println("error:", err) } else { fmt.Println(vstring) } err = libreflect.Set(reflect.ValueOf(&vstring), "and I will write you a tragedy") if err != nil { fmt.Println("error:", err) } else { fmt.Println(vstring) } }
Output:
error: Set: object []string is not setable [a hero] [a hero and I will write you a tragedy]
Example (Unmarshal)¶
Code:play
package main import ( "fmt" "math/big" "net/url" "reflect" libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect" ) func main() { var ( rat = big.NewRat(0, 1) myURL = &url.URL{} bigInt = big.NewInt(1) err error ) // This Set will call UnmarshalText on big.Rat. err = libreflect.Set(reflect.ValueOf(rat), "1.234") if err != nil { fmt.Println("error:", err) } else { fmt.Println(rat.FloatString(4)) } err = libreflect.Set(reflect.ValueOf(rat), "") if err != nil { fmt.Println("error:", err) } else { fmt.Println(rat.FloatString(4)) } // This Set will call UnmarshalBinary on url.URL. err = libreflect.Set(reflect.ValueOf(myURL), "https://kilabit.info") if err != nil { fmt.Println("error:", err) } else { fmt.Println(myURL) } // This Set will call UnmarshalJSON. err = libreflect.Set(reflect.ValueOf(bigInt), "123_456") if err != nil { fmt.Println("error:", err) } else { fmt.Println(bigInt) } err = libreflect.Set(reflect.ValueOf(bigInt), "") if err != nil { fmt.Println("error:", err) } else { fmt.Println(bigInt) } }
Output:
1.2340 0.0000 https://kilabit.info 123456 0
func Tag ¶
Tag simplify lookup on struct's field tag.
Given a StructField and the name of tag, return the tag's value and options inside the tag. The options is any string after tag's value, separated by comma. For example, given the following field definition
F `tag:"name,opt1, opt2"`
It will return (name, [opt1 opt2], true).
If the field is exported but does not have tag, it will return the field name (as is without converting to lower case) in val with hasTag is false: (Name, nil, false).
If the field is unexported or tag is "-" it will return empty val with
hasTag is false ("", nil, false).
Code:play
Output:Example¶
package main
import (
"fmt"
"reflect"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
func main() {
type T struct {
F1 int `atag:" f1 , opt1 , opt2 ,"`
F2 int `atag:", opt1"`
F3 int
F4 int `atag:" - ,opt1"`
}
var (
t T
vtype reflect.Type
field reflect.StructField
val string
opts []string
hasTag bool
)
vtype = reflect.TypeOf(t)
for x := range vtype.NumField() {
field = vtype.Field(x)
val, opts, hasTag = libreflect.Tag(field, "atag")
fmt.Println(val, opts, hasTag)
}
}
f1 [opt1 opt2 ] true
F2 [opt1] false
F3 [] false
[] false
func Unmarshal ¶
Unmarshal set the obj value by calling one of the method: UnmarshalBinary, UnmarshalJSON, or UnmarshalText; in respective order.
Just like reflect, the obj value must be pointer to initialized variable (&T) or pointer-to-pointer to uninitialized variable (**T).
If obj implement one of the method, it will return (true, nil) if there is no error.
If none of the method exist on obj, it will return (false, nil).
Code:play
Output: Code:play
Output: Code:play
Output:Example (UnmarshalBinary)¶
package main
import (
"fmt"
"log"
"net/url"
"reflect"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
func main() {
var (
val = []byte("https://kilabit.info")
err error
ok bool
)
// Passing variable will not work...
var varB url.URL
ok, err = libreflect.Unmarshal(reflect.ValueOf(varB), val)
if err != nil {
return
}
fmt.Println(varB.String(), ok)
// Pass it like these.
ok, err = libreflect.Unmarshal(reflect.ValueOf(&varB), val)
if err != nil {
log.Fatal(err)
}
fmt.Println(varB.String(), ok)
// Passing un-initialized pointer also not working...
var varPtrB *url.URL
ok, err = libreflect.Unmarshal(reflect.ValueOf(varPtrB), val)
if err != nil {
log.Fatal(err)
}
fmt.Println(varPtrB, ok)
// Pass it as **T.
ok, err = libreflect.Unmarshal(reflect.ValueOf(&varPtrB), val)
if err != nil {
log.Fatal(err)
}
fmt.Println(varPtrB, ok)
var ptrB = &url.URL{}
ok, err = libreflect.Unmarshal(reflect.ValueOf(&ptrB), val)
if err != nil {
log.Fatal(err)
}
fmt.Println(ptrB, ok)
}
false
https://kilabit.info true
<nil> false
https://kilabit.info true
https://kilabit.info true
Example (UnmarshalJSON)¶
package main
import (
"fmt"
"math/big"
"reflect"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
func main() {
var (
vals = [][]byte{
[]byte("123.456"),
[]byte("123_456"),
[]byte("123456"),
}
bigInt = big.NewInt(1)
val []byte
err error
)
for _, val = range vals {
_, err = libreflect.Unmarshal(reflect.ValueOf(bigInt), val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(bigInt)
}
}
}
Unmarshal: math/big: cannot unmarshal "123.456" into a *big.Int
123456
123456
Example (UnmarshalText)¶
package main
import (
"fmt"
"math/big"
"reflect"
libreflect "git.sr.ht/~shulhan/pakakeh.go/lib/reflect"
)
func main() {
var (
vals = [][]byte{
[]byte(""),
[]byte("123.456"),
[]byte("123_456"),
[]byte("123456"),
}
r = big.NewRat(0, 1)
val []byte
err error
)
for _, val = range vals {
_, err = libreflect.Unmarshal(reflect.ValueOf(r), val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(r)
}
}
}
0/1
15432/125
123456/1
123456/1
Types ¶
type Equaler ¶
type Equaler interface { // Equal compare the struct receiver with parameter v. // The v value can be converted to struct type T using (*T). // If both struct values are equal it should return nil. Equal(v any) error }
Equaler is an interface that when implemented by a struct type, it will
be used to compare the value in DoEqual or IsEqual.
Code:play
Example¶
// SPDX-FileCopyrightText: 2024 M. Shulhan <ms@kilabit.info>
//
// SPDX-License-Identifier: BSD-3-Clause
package main
import (
"fmt"
"log"
)
type ADT struct {
vint int
}
func (rnp *ADT) Equal(v any) (err error) {
var (
logp = `Equal`
got *ADT
ok bool
)
got, ok = v.(*ADT)
if !ok {
return fmt.Errorf(`%s: v type is %T, want %T`, logp, got, v)
}
if rnp.vint != got.vint {
return fmt.Errorf(`%s: vint: %d, want %d`,
logp, got.vint, rnp.vint)
}
return nil
}
func main() {
var (
rp1 = ADT{
vint: 1,
}
rp2 = ADT{
vint: 2,
}
)
var err = DoEqual(&rp1, &rp2)
if err == nil {
log.Fatal(`expecting error, got nil`)
}
var exp = `Equal: vint: want 1, got 2`
var got = err.Error()
if exp != got {
log.Fatalf(`want %q, got %q`, exp, got)
}
}
Source Files ¶
- Version
- v0.60.0 (latest)
- Published
- Feb 1, 2025
- Platform
- linux/amd64
- Imports
- 5 packages
- Last checked
- 9 hours ago –
Tools for package owners.