Is that possible to create a comparison operator from string? - go

I'm trying to create a function that will produce an if condition from a predefined array.
for example:
package errors
type errorCase struct {
// This is the field I need to get in another struct
Field string
// The comparison operator
TestOperator string
// The value that the expected one should not with equal...
WrongValue interface{}
}
var ErrorCases = []*errorCase{ {
"MinValue",
"<",
0,
}, {
"MaxValue",
"==",
0,
}}
Actually I made a new function with a for loop that iterate through all of these "error cases"
func isDirty(questionInterface models.QuestionInterface) bool {
for _, errorCase := range errors.ErrorCases {
s := reflect.ValueOf(&questionInterface).Elem()
value := s.Elem().FieldByName(errorCase.Field)
// At this point I need to create my if condition
// to compare the value of the value var and the wrong one
// With the given comparison operator
}
// Should return the comparison test value
return true
}
Is that possible to create an if condition like that?
With the reflect package?
I think this is possible but I don't find where I should start.

This is possible. I built a generic comparison library like this once before.
A comparison, in simple terms, contains 3 parts:
A value of some sort, on the left of the comparison.
An operator (=, <, >, ...).
A value of some sort, on the right of the comparison.
Those 3 parts, contain only two different types - value and operator. I attempted to abstract those two types into their base forms.
value could be anything, so we use the empty interface - interface{}.
operator is part of a finite set, each with their own rules.
type Operator int
const (
Equals Operator = 1
)
Evaluating a comparison with an = sign has only one rule to be valid - both values should be of the same type. You can't compare 1 and hello. After that, you just have to make sure the values are the same.
We can implement a new meta-type that wraps the requirement for evaluating an operator.
// Function signature for a "rule" of an operator.
type validFn func(left, right interface{}) bool
// Function signature for evaluating an operator comparison.
type evalFn func(left, right interface{}) bool
type operatorMeta struct {
valid []validFn
eval evalFn
}
Now that we've defined our types, we need to implement the rules and comparison functions for Equals.
func sameTypes(left, right interface{}) bool {
return reflect.TypeOf(left).Kind() == reflect.TypeOf(right).Kind()
}
func equals(left, right interface{}) bool {
return reflect.DeepEqual(left, right)
}
Awesome! So we can now validate that our two values are of the same type, and we can compare them against each other if they are. The last piece of the puzzle, is mapping the operator to its appropriate rules and evaluation and having a function to execute all of this logic.
var args = map[Operator]operatorMeta{
Equals: {
valid: []validFn{sameTypes},
eval: equals,
},
}
func compare(o Operator, left, right interface{}) (bool, error) {
opArgs, ok := args[o]
if !ok {
// You haven't implemented logic for this operator.
}
for _, validFn := range opArgs.valid {
if !validFn(left, right) {
// One of the rules were not satisfied.
}
}
return opArgs.eval(left, right), nil
}
Let's summarize what we have so far:
Abstracted a basic comparison into a value and operator.
Created a way to validate whether a pair of values are valid for an operator.
Created a way to evaluate an operator, given two values.
(Go Playground)
I hope that I gave some insight into how you can approach this. It's a simple idea, but can take some boilerplate to get working properly.
Good luck!

Related

Reason of third return statement in method

I’m new to Go and to practice I do some coding exercice on Exercism. I stubbled on a particular exercice in which I’m having a hard time undestanding the solution. Here’s the code:
// Ints defines a collection of int values
type Ints []int
// Lists defines a collection of arrays of ints
type Lists [][]int
// Strings defines a collection of strings
type Strings []string
// Keep filters a collection of ints to only contain the members where the provided function returns true.
func (i Ints) Keep(strainer func(int) bool) (o Ints) {
for _, v := range i {
if strainer(v) {
o = append(o, v)
}
}
return
}
// Discard filters a collection to only contain the members where the provided function returns false.
func (i Ints) Discard(strainer func(int) bool) Ints {
return i.Keep(func(n int) bool { return !strainer(n) })
}
My Problem comes with the Discard Method, I dont understand the second return statement in the curly braces since the Keep function is suppose to return a value of type Ints and not a boolean statement unless I missed something, if someone could break down the Discard function for me it would be helpful.
Thanks
The Keep method takes a function as a parameter. It expects it to be func (int) bool - a function taking an int and returning a bool.
When Keep is invoked in Discard, the code passes it an anonymous function with the right signature (take int, return bool). This anonymous function invokes strainer (which is a function passed into Discard) and returns its response, negated.
The idea is that strainer is a filter function: it tells you which elements to keep. So the implementation of Keep is straightforward: iterate over all elements, and keep only those for which strainer returns true.
Discard is written in a clever way using Keep, instead of also writing a loop like this:
func (i Ints) Discard(strainer func(int) bool) (o Ints) {
for _, v := range i {
if !strainer(v) {
o = append(o, v)
}
}
return
}
It instead invokes Keep with a function that inverts the result of strainer.

Idiomatic and DRY solution to merging arrays of arbitrary types

I want to create a utility-function that is able to merge two given slices, determining equality by a given function.
type IsEqualTest func(interface{}, interface{}) bool
func ArrayMerge(one *[]interface{}, another *[]interface{}, comp IsEqualTest) *[]interface{} {
merged := *one
for _, element := range *another {
if !ArrayContains(one, &element, comp) {
merged = append(merged, element)
}
}
return &merged
}
func ArrayContains(container *[]interface{}, eventualContent *interface{}, comp IsEqualTest) bool {
for _, element := range *container {
if comp(element, eventualContent) {
return true
}
}
return false
}
// please don't mind the algorithmic flaws
However, as go does treat the []interface{} type as non-compatible to slices of anything (and it lacks generics), I would need to iterate over both operands, converting the type of the contained elements when calling, which is not what anyone could want.
What is the Go style of dealing with collections containing any type?
First: without generics, there is no idiomatic way of doing this.
Second: your thinking might be too influenced by other languages. You already got a function to compare, why not take it a bit further?
What I suggest below is not efficient, and it should not be done. However, if you really want to do it:
It looks like this is not a set union, but add the elements of the second slice to the first if they don't already exist in the first slice. To do that, you can pass two functions:
func merge(len1,len2 int, eq func(int,int)bool, write func(int)) {
for i2:=0;i2<len2;i2++ {
found:=false
for i1:=0;i1<len1;i1++ {
if eq(i1,i2) {
found=true
break
}
}
if !found {
write(i2)
}
}
Above, eq(i,j) returns true if slice1[i]==slice2[j], and write(j) does append(result,slice2[j]).

How to resolve whether pass objects via interface{} have not initializated fields

I have problem with resolve whether object which was pass as interface to function hasn't initializated fields, like object which was defined as just someObject{} is a empty, because all fields, has value 0, or nil
Problem becomes more complicated if I pass diffrent objects, because each object have diffrent type field value so on this moment I don't find universal way to this.
Example
func main(){
oo := objectOne{}
ot := objectTwo{}
oth := objectThree{"blah" , "balbal" , "blaal"}
resolveIsNotIntialized(oo)
resolveIsNotIntialized(ot)
resolveIsNotIntialized(oth)
}
func resolveIsNotIntialized(v interface{}) bool{
// and below, how resolve that oo and ot is empty
if (v.SomeMethodWhichCanResolveThatAllFiledIsNotIntialized){
return true
}
return false
}
I want to avoid usage switch statement like below, and additional function for each object, ofcorse if is possible.
func unsmartMethod(v interface{}) bool{
switch v.(type){
case objectOne:
if v == (objectOne{}) {
return true
}
// and next object, and next....
}
return false
}
As Franck notes, this is likely a bad idea. Every value is always initialized in Go. Your actual question is whether the type equals its Zero value. Generally the Zero value should be designed such that it is valid. The better approach would generally be to create an interface along the lines of:
type ZeroChecker interface {
IsZero() bool
}
And then attach that to whatever types you want to check. (Or possibly better: create an IsValid() test instead rather than doing your logic backwards.)
That said, it is possible to check this with reflection, by comparing it to its Zero.
func resolveIsNotIntialized(v interface{}) bool {
t := reflect.TypeOf(v)
z := reflect.Zero(t).Interface()
return reflect.DeepEqual(v, z)
}
(You might be able to get away with return v == z here; I haven't thought through all the possible cases.)
I don’t think there is a good reason (in idiomatic Go) to do what you are trying to do. You need to design your structs so that default values (nil, empty string, 0, false, etc.) are valid and represent the initial state of your object. Look at the source of the standard library, there are lots of examples of that.
What you are suggesting is easily doable via Reflection but it will be slow and clunky.
You could narrow the type which your function takes as an argement a little, not take an interface{} but accept one that allows you to check for non-zero values, say type intercae{nonZero() bool} as in the example code below. This will not tell you explicitly that it hasn't been set to the zero value, but that it is not zero.
type nonZeroed interface {
nonZero() bool
}
type zero struct {
hasVals bool
}
func (z zero) nonZero() bool {
return z.hasVals
}
type nonZero struct {
val int
}
func (nz nonZero) nonZero() bool {
return nz.val != 0
}
type alsoZero float64
func (az alsoZero) nonZero() bool {
return az != 0.0
}
func main() {
z := zero{}
nz := nonZero{
val: 1,
}
var az alsoZero
fmt.Println("z has values:", initialized(z))
fmt.Println("nz has values:", initialized(nz))
fmt.Println("az has values:", initialized(az))
}
func initialized(a nonZeroed) bool {
return a.nonZero()
}
Obviously as the type get more complex additional verification would need to be made that it was "nonZero". This type of pattern could be used to check any sort condition.

In Go, is there any way to compare two mixed-type interfaces without nested switch statements?

Go's interface{} type is both the best and most annoying feature of the language, I find. I'm trying to create a simple user-customisable validation rule solution where the user can define:
The comparison operator.
The comparison operand.
The map key that leads to the value to test.
As well as a simple Boolean expression parser that allows the user to combine multiple rules using AND and OR. So far it all works well, the expressions can be parsed, tokenised, and evaluated successfully, but it's running the rules on the given data that causes problems.
This is the current version of the function that actually evaluates the data:
/*
validate returns a boolean value denoting whether a test was successful. This
function will panic if the type assertions fail.
*/
func (sfvre standardFieldValidationRuleEntry) validate(fieldValue interface{}) bool {
switch sfvre.Operator() {
case VROP_EQUAL:
return fieldValue == sfvre.ComparisonOperand()
case VROP_NEQUAL:
return fieldValue != sfvre.ComparisonOperand()
case VROP_GT:
return fieldValue.(int) > sfvre.ComparisonOperand().(int)
case VROP_LT:
return fieldValue.(int) < sfvre.ComparisonOperand().(int)
case VROP_GTET:
return fieldValue.(int) >= sfvre.ComparisonOperand().(int)
case VROP_LTET:
return fieldValue.(int) <= sfvre.ComparisonOperand().(int)
case VROP_CONTAINS:
return strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
case VROP_NCONTAINS:
return !strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
default:
return false
}
}
At the moment the operator implies whether the data is numeric (greater than, less than, etc.). The type assertion to int did the job while building the other parts of the package, but the finished system should also be able to take float64 and be able to handle mixed type comparisons.
The only way I can see of doing this at the moment is by having multiple nested type switches, a level for each of:
The operator.
The type of the field value given.
The type of the comparison operand.
But this has the potential to become very large and not easily manageable. Is there a 'cleaner' way to do this that I can't see, or am I stuck using nested switches?
The solution I've got as of now (thanks to #Volker for the suggestion) does a quick type switch on the values that need comparing and then instead of using the originals in the Operator() switch, it uses the concrete float values:
/*
validate returns a boolean value denoting whether a test was successful. This
function will panic if the type assertions fail.
*/
func (sfvre standardFieldValidationRuleEntry) validate(fieldValue interface{}) bool {
var floatFieldVal, floatCompVal float64
//If the interface is int or float, convert it to a statically typed float64.
switch fieldValue.(type) {
case int:
floatFieldVal = float64(fieldValue.(int))
case float64:
floatFieldVal = fieldValue.(float64)
}
//Do the same with the comparison value.
switch sfvre.ComparisonOperand().(type) {
case int:
floatCompVal = float64(sfvre.ComparisonOperand().(int))
case float64:
floatCompVal = sfvre.ComparisonOperand().(float64)
}
switch sfvre.Operator() {
case VROP_EQUAL:
return fieldValue == sfvre.ComparisonOperand()
case VROP_NEQUAL:
return fieldValue != sfvre.ComparisonOperand()
case VROP_GT:
return floatFieldVal > floatCompVal
case VROP_LT:
return floatFieldVal < floatCompVal
case VROP_GTET:
return floatFieldVal >= floatCompVal
case VROP_LTET:
return floatFieldVal <= floatCompVal
case VROP_CONTAINS:
return strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
case VROP_NCONTAINS:
return !strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
default:
return false
}
}
It doesn't catch everything, but restricting what operators the user can choose based on what field they're comparing can mitigate this, but that's part of the larger solution so irrelevant here.

Use one return value?

I want to call my function test and use one of the return values. How do I say give me the first or second value? I thought the below would give me "one" but [1] is incorrect usage causing a compile error
package main
import (
"fmt"
)
func test() (int, string) { return 1, "one"; }
func main() {
i,sz:=test()
fmt.Printf("%d=%s\n",i,sz)
fmt.Printf("%s", test()[1]) //error
}
As far as I know, you can't subscript function return values. You can do:
_, someString := test();
fmt.Println(someString);
Citing the Go Language Specification:
A primary expression of the form a[x]
denotes the element of the array, slice, string or map a indexed by x. The value x is called the index or map key, respectively. [...] Otherwise [if a is not an array, slice string or map] a[x] is illegal.
Multiple return values in Go, however, are not arrays being returned, but a separate language feature. This must be so, because an array can only hold elements of a single type, but return values can be of different types.
But since return values are not arrays (or slices, strings or maps), the a[x] syntax is, per language spec, a syntax error. As a result, as #dav has already correctly stated, you will have to actually assign the return value to a variable in order to use it elsewhere.
In special cases, you may be able to use this bit of trivia to avoid variable assignment:
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
Which makes the following possible:
func foo() (int, string) {
return 42, "test";
}
func bar(x int, s string) {
fmt.Println("Int: ", x);
fmt.Println("String: ", s);
}
func main() {
bar(foo())
}

Resources