structure: Add Has() method, fix IsZero()

This commit is contained in:
Fatih Arslan 2014-07-30 22:01:18 +03:00
parent e68f708c4c
commit 31b952e111
4 changed files with 103 additions and 17 deletions

View File

@ -45,8 +45,12 @@ f := structure.Fields(s)
// => "Server"
n := structure.Name(s)
// Check if field name exists
// => true
n := structure.Has(s, "Enabled")
// Check if the fields of a struct is initialized or not.
if structure.IsZero(s) {
if !structure.IsZero(s) {
fmt.Println("s is initialized")
}

View File

@ -80,7 +80,7 @@ func Values(s interface{}) []interface{} {
}
// IsZero returns true if all fields in a struct are initialized (non zero
// IsZero returns true if any field in a struct is not initialized (zero
// value). A struct tag with the content of "-" ignores the checking of that
// particular field. Example:
//
@ -96,8 +96,8 @@ func IsZero(s interface{}) bool {
val := v.Field(i)
if IsStruct(val.Interface()) {
ok := IsZero(val.Interface())
if !ok {
return false
if ok {
return true
}
continue
@ -110,11 +110,11 @@ func IsZero(s interface{}) bool {
current := v.Field(i).Interface()
if reflect.DeepEqual(current, zero) {
return false
return true
}
}
return true
return false
}
// Fields returns a slice of field names. A struct tag with the content of "-"
@ -172,6 +172,28 @@ func Name(s interface{}) string {
return t.Name()
}
// Has returns true if the given field name exists for the struct s. It panic's
// if s's kind is not struct.
func Has(s interface{}, fieldName string) bool {
v, fields := strctInfo(s)
for i, field := range fields {
val := v.Field(i)
if IsStruct(val.Interface()) {
if ok := Has(val.Interface(), fieldName); ok {
return true
}
}
if field.Name == fieldName {
return true
}
}
return false
}
// strctInfo returns the struct value and the exported struct fields for a
// given s struct. This is a convenient helper method to avoid duplicate code
// in some of the functions.

View File

@ -110,7 +110,7 @@ func ExampleIsZero() {
a := &Access{
LastAccessed: time.Now(),
}
validA := IsZero(a)
isZeroA := IsZero(a)
// Name and Number is initialized.
b := &Access{
@ -118,11 +118,31 @@ func ExampleIsZero() {
LastAccessed: time.Now(),
Number: 12345,
}
validB := IsZero(b)
isZeroB := IsZero(b)
fmt.Printf("%#v\n", validA)
fmt.Printf("%#v\n", validB)
fmt.Printf("%#v\n", isZeroA)
fmt.Printf("%#v\n", isZeroB)
// Output:
// false
// true
// false
}
func ExampleHas() {
type Access struct {
Name string
LastAccessed time.Time
Number int
}
s := &Access{
Name: "Fatih",
LastAccessed: time.Now(),
Number: 1234567,
}
found := Has(s, "LastAccessed")
fmt.Printf("Has: %+v\n", found)
// Output:
// Has: true
}

View File

@ -357,8 +357,8 @@ func TestIsZero(t *testing.T) {
}
ok := IsZero(T)
if ok {
t.Error("IsZero should return false because D is not initialized")
if !ok {
t.Error("IsZero should return true because A and B are initialized.")
}
var X = struct {
@ -369,8 +369,21 @@ func TestIsZero(t *testing.T) {
}
ok = IsZero(X)
if !ok {
t.Error("IsZero should return true because A is initialized")
}
var Y = struct {
A string
B int
}{
A: "a-value",
B: 123,
}
ok = IsZero(Y)
if ok {
t.Error("IsZero should return false because F is not initialized")
t.Error("IsZero should return false because A and B is initialized")
}
}
@ -388,8 +401,8 @@ func TestIsZero_Nested(t *testing.T) {
b := &B{A: a, C: 123}
ok := IsZero(b)
if ok {
t.Error("IsZero should return false because D is not initialized")
if !ok {
t.Error("IsZero should return true because D is not initialized")
}
}
@ -408,11 +421,38 @@ func TestIsZero_Anonymous(t *testing.T) {
b.A = a
ok := IsZero(b)
if ok {
if !ok {
t.Error("IsZero should return false because D is not initialized")
}
}
func TestHas(t *testing.T) {
type A struct {
Name string
D string
}
a := A{Name: "example"}
type B struct {
A
C int
}
b := &B{C: 123}
b.A = a
if !Has(b, "Name") {
t.Error("Has should return true for Name, but it's false")
}
if Has(b, "NotAvailable") {
t.Error("Has should return false for NotAvailable, but it's true")
}
if !Has(b, "C") {
t.Error("Has should return true for C, but it's false")
}
}
func TestName(t *testing.T) {
type Foo struct {
A string