Is it possible to use an operator in place of a function in go?
For example, in the following code is it possible to replace add with +?
package main
import "fmt"
var cur, prev int = 1, 1
func fib(f func(int, int) int) int {
return f(cur, prev)
}
func main() {
add := func(x int, y int) int { return x + y };
fmt.Println(fib(add))
}
If it's not possible to use operators as functions, then I would appreciate a link to the documentation clarifying this.
Operators are not first-class values in Go (nor most other languages), so no, you cannot pass them as arguments. Notice that even the Go documentation uses a func(x,y int) int { return x+y } in its examples.
Also note that the grammar for operators does not allow any options for an operator without a corresponding expression to operate on.
Related
trying to check if a given number is less than the other or not, so wrote the below:
package main
import "fmt"
type T interface {}
func Less(i, j T) bool {
return i > j
}
But got the below error:
# command-line-arguments
.\hashmap.go:23:11: invalid operation: i > j (operator > not defined on interface)
How can I add such mathematical operations to general type element (number or string)?
interface is not a type, nor is it a generic value representing intersection of all types like string and int. When you ask for whether a is greater than or equal to b, you'll have to also specify which exact types those two belong (implicitly, they should have the same type), to answer that question. Similarly, Go also needs that information. Doing that for interface can be come a little cumbersome. However, there are a couple of ways:
Define the Less function individually on both types:
func LessString(n1, n2 string) bool {
return strings.Compare(n1, n2) == -1
}
// no need to define a less function, but whatever
func LessInt(n1, n2 int) bool {
return n1 < n2
}
Or, using type aliases:
type Name string
type Age int
func (name Name) Less(compare string) bool {
return strings.Compare(string(name), compare) == -1
}
func (age Age) LessInt(compare int) bool {
return int(age) < compare
}
A second way to implement Less functionality on interface would be to do type assertions:
// This isn't all that useful, but whatever
type T interface{}
func main() {
fmt.Println(Less(10, 20))
fmt.Println(Less("10", "20"))
}
func Less(t1, t2 T) bool {
switch v1 := t1.(type) {
case string:
return strings.Compare(v1, t2.(string)) < 0 // import "strings"
// return v1 < t2.(string)
case int:
return v1 < t2.(int)
}
return false
}
There is no way in Go to define operators over types. It prefers adding functions to achieve that. Many standard library modules follow similar patterns.
What is the Go equivalent of, for example, Python's operator package for calling builtin operators by name?
Meaning, how can I do something like:
func f(op func(int, int)bool, a int, b int)
...
if op(a, b) {
...
f(operators.LessThan, 1, 2) // true
Stated otherwise, how to write a function that takes in what basic operator to apply as a function argument?
First, you shouldn't assume language X has any equivalent for feature Y in language Z. Also you should write/design code for the language you're using rather than designing as if it was another language and then translating line-by-line or function-by-function.
As comments mentioned, operators are builtin in Go with no operator overloading or functional equivalents. If you haven't already you should take the Go Tour and read the Language Specification to see what Go does have.
If you really want/need to do something like you ask this is one way:
package main
import "fmt"
type Compare func(int, int) bool
func DoCompare(cmp Compare, a, b int) bool {
return cmp(a, b)
}
var (
CmpLessThan = func(a, b int) bool { return a < b }
CmpLessThanOrEqual = func(a, b int) bool { return a <= b }
CmpGreaterThan = func(a, b int) bool { return a > b }
CmpGreaterThanOrEqual = func(a, b int) bool { return a >= b }
)
func main() {
fmt.Println(DoCompare(CmpLessThan, 1, 2))
}
Go Playground.
Normally if something like this is needed, instead of multiple comparison functions, a single compare function is used that returns <0, 0, or, >0 (e.g. -1, 0, +1) for less-than, equal, greater-than. For example, big.Int.Cmp.
Update 2023 / Go with Generics
Powered by Go generics, I made a new package to do this at github.com/tawesoft/golib/v2/operator:
For your example use case,
import "tawesoft/golib/v2/operator"
...
f := operator.LT[int] // less than
f(1, 2) // true
Old answer
I needed the same thing - basic operators as first-class functions in Go - and ended up writing a template and a bit of Python to generate my own.
I've packaged it up into a single well-tested Go module, called operator after the Python module.
Hope this helps!
Go Get:
go get -u tawesoft.co.uk/go/operator
Examples:
operator.Boolean.Not(true) == false
operator.Boolean.Nary.Any(false, true, true, false) == true
operator.Int.Binary.Add(1, 2) == 3
In your case:
f(operator.Int.Binary.Lt, 1, 2)
This question already has answers here:
X does not implement Y (... method has a pointer receiver)
(4 answers)
Closed 4 years ago.
Lets take this very small example, having a function that modify value inside the struct:
package learn
type Point struct {
x int
y int
}
func (p *Point) Set(x int, y int) {
p.x = x
p.y = y
}
this works properly, used like this for instance:
package main
import (
"NewPattern/learn"
"fmt"
)
func main() {
p := learn.Point{}
p.Set(5, 6)
fmt.Print(p)
}
it outputs the expected value: {5,6}
Now let's say I don't want the user having a constructor, I can change the code by adding this function:
func NewPoint(x int, y int) Point {
return Point{x, y}
}
then I can use in main like this:
func main() {
p := learn.NewPoint(3, 8)
fmt.Print(p)
p.Set(5, 6)
fmt.Print(p)
}
and it works as expected returning {3 8}{5 6}.
Well now we want to prevent creating point without calling the constructor - not really the case here, but can make sense for complex classes - so we avoid exporting Point and we create an interface instead, so I refactored the code like this: (this is not working!)
package learn
type point struct {
x int
y int
}
type Point interface {
Set(x int, y int)
}
func (p *point) Set(x int, y int) {
p.x = x
p.y = y
}
func NewPoint(x int, y int) Point {
return point{x, y} //error here
}
This says:
cannot use point literal (type point) as type Point in return argument:
point does not implement Point (Set method has pointer receiver)
I can "fix" this by modifying the method in:
func NewPoint(x int, y int) point {
return point{x, y}
}
but this just move the error in main, that is refactored like:
func main() {
var p learn.Point
p = learn.NewPoint(3, 8) //error here!
fmt.Print(p)
p.Set(5, 6)
fmt.Print(p)
}
and the error is:
cannot use learn.NewPoint(3, 8) (type learn.point) as type learn.Point in assignment:
learn.point does not implement learn.Point (Set method has pointer receiver)
by googling I managed to solve in this way:
func NewPoint(x int, y int) *point {
return &point{x, y}
}
but as a result in the main we are obtaining: &{3 8}&{5 6} as a print, ad as well I don't get actually what is happening behind the scenes.
I guess this is somehow related by having things passed and maybe "returned" by value, is this the case? But I don't know how the first examples without interface worked without effort. Can please someone clarify these details that I think are essential to Go understanding.
point and *point (i.e the pointer to point) are two different types. In your code the interface Point is implemented by *point type. You can implement the constructor as:
func NewPoint(x int, y int) Point {
return &point{x, y}
}
The printing will show & befor the points value as the underlying value is a pointer.
I have a program as below:
package main
//Define declare variables
type Define struct {
len int
breath int
}
//Area calculate area
func (e *Define) Area() (a int) {
a = e.len * e.breath
return a
}
I call the above program in :
package main
func main() {
y := Define{10, 10}
x := y.Area()
print(x)
}
I would like make the function Area() as part of struct initialization. Currently, I have to create a new object for "Define" ie "y" and then call the method Area. Instead is there a way that Area methods auto calculates once I create the object?
I'd rename Define to something better like Geometry. Usually in Golang, New... is used as a "constructor"
Since you said you wanted area to be autocalculated, include the area as a struct field. Here's how I'd go about it (https://play.golang.org/p/4y6UVTTT34Z):
package main
//variables
type Geometry struct {
len int
breath int
area int
}
// Constructor
func NewGeometry(len int, breadth int) *Geometry {
g := &Geometry{len, breadth, Area(len, breadth)}
return g
}
//Area calculate area
func Area(len, breadth int) (a int) {
return len * breadth
}
func main() {
g := NewGeometry(10, 2)
fmt.Println(g.area)
}
Go has the concept of "Constructors" that may cover your use case. Combined with exporting it allows you to encapsulate initialization by hiding specifics of calculation from callers:
package main
//Define declare variables
type Define struct {
len int
breath int
area int
}
func (e Define) Area() int {
return e.area
}
func NewDefine(l, b int) Define {
d := Define{
len: l,
breath: b,
area: calculateArea(l, b),
}
return d
}
The pattern to focus on is the exported NewX. It is extremely common to see constructors named NewX which will initialize and return a struct. The above delegates to an un-exported calculateArea function. Of course there are many different possible ways for you to structure your program. calculateArea still encapsulates the area calculation for trivial unit testing, while hiding it from callers by not exporting it.
Here's the sample code (from tour.golang.org),
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
x, _ := split(17)
fmt.Println(x)
}
I would like to know if it is possible to shorten the main function to just a single line. Logically there should be a way (might not look very elegant in this case though) to access only first result parameter returned from function and print it.
fmt.Println is a variadic function, so you can just pass the split function as a parameter:
func main() {
fmt.Println(split(17))
}
see it working in full here: http://play.golang.org/p/c1zkFVMe11