How to fix 'declared but not used' compiler error in this simple program? - go

I am trying to learn Go. I really don't understand why the compiler is saying that I am not using a variable. It seems to me that I am using the variable as an argument to Println.
My textbook states:
In this for loop i represents the current position in the array and
value is the same as x[i]
package main
import "fmt"
func main() {
x := [5]float64{ 1,2,3,4,5 }
i := 0
var total float64 = 0
for i, value := range x {
total += value
fmt.Println(i, value)
}
fmt.Println("Average:", total / float64(len(x)))
}
Output on OS X:
go run main.go
# command-line-arguments
./main.go:8: i declared and not used
Surely this fmt.Println(i, value) is using the variable i?

How to fix the compiler message?
Remove the outer i from your program:
package main
import "fmt"
func main() {
x := [5]float64{1, 2, 3, 4, 5}
var total float64 = 0
for i, value := range x {
total += value
fmt.Println(i, value)
}
fmt.Println("Average:", total/float64(len(x)))
}
Surely this fmt.Println(i, value) is using the variable i?
Yes, but the one you're defining inside the for loop. (note the :=), here:
for i, value := range x
^ ^
The outer variable i is never used.

Related

How to change elements in a list?

If I use container/list as
package main
import (
"container/list"
"fmt"
)
type Data struct {
x int
}
func main() {
l := list.New()
l.PushBack(Data{2})
a := l.Back()
v := a.Value.(Data)
v.x = 1
fmt.Println(l.Back().Value) // --> {2}
}
Well, the value of x in the list does not change. What is the correct programming pattern?
Function arguments and return values are passed by value in Go. Therefore v is a copy of the original Data value. Changing it does not affect the one that is stored in the list.
You can get the behaviour you want by inserting a pointer to a Data value instead:
l := list.New()
l.PushBack(&Data{2})
a := l.Back()
v := a.Value.(*Data)
v.x = 1
fmt.Println(l.Back().Value) // --> &{1}

writing to a pointer but the compiler still complains unused variable

The following code causes a compilation error:
main.go:8:9: p declared and not used
package main
func main() {
pointers := make([]*int, 5)
a := 1 // create an int
for _, p := range pointers {
p = &a
}
}
Writing to p doesn't count as using it?
P is only scoped to the loop block and essentially gets a copy of a pointers slice element every time it goes through the loop. This would work though:
package main
import "fmt"
func main() {
pointers := make([]*int, 5)
a := 1 // create an int
for i := range pointers {
pointers[i] = &a
}
fmt.Println(pointers)
}
Playground

Randomly generating a matrix in Golang

I'm currently writing a program and I want to randomly generate a matrix.
Currently I'm pre-setting the values in it as follows:
m1 := [3][3]int{
[3]int{1, 1, 1},
[3]int{4, 1, 7},
[3]int{1, 65, 1},
}
However I want the values inputted to be randomly generated in a range from 1-100.
import "math/rand"
I am importing the above library and trying to utilise it.
I have attempted to get this working however can't seem to make any headway.
m1 := [3][3]int{
[3]int{rand.Intn, 1, 1},
[3]int{4, 1, 7},
[3]int{1, 65, 1},
}
I have attempted to complete it with the above solution to make the first number random however I get the following error.
cannot use rand.Intn (type func(int) int) as type int in array or slice literal
Any help greatly appreciated.
The direct answer is the fact that rand.Intn() generates a random integer between 0 and n, where n is a parameter to this method. The error that you are getting is the compiler complaining that you are trying to initialize an int value with a function that requires two ints and returns one - you are trying to assign a function to an int. So the correct call would be something like rand.Intn(100), which will give you a random number between 0 - 100.
However, why do it this way? Why not dynamically initialize your array with random numbers as:
m1 := [3][3]int{}
for i:=0; i<3; i++ {
for j:=0; j<3; j++ {
m1[i][j] = rand.Int()
}
}
Answer to your question is answered above, this is an extension,
While rand.Int(10) always gives you 1, as it isn't seeded,
you can add this function to get random values each time you run your program,
package main
import (
"fmt"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
//we are seeding the rand variable with present time
//so that we would get different output each time
}
func main() {
randMatrix := make([][]int, 3)
// we have created a slice with length 3
//which can hold type []int, these can be of different length
for i := 0; i < 3; i++ {
randMatrix[i] = make([]int, 3)
// we are creating a slice which can hold type int
}
generate(randMatrix)
fmt.Println(randMatrix)
}
func generate(randMatrix [][]int) {
for i, innerArray := range randMatrix {
for j := range innerArray {
randMatrix[i][j] = rand.Intn(100)
//looping over each element of array and assigning it a random variable
}
}
}
This code generates random Matrix, below 100, while you can also use flags for any kind of future use and generalize the values,
import "flag"
var outerDim, innerDim, limit *int
func main() {
outerDim = flag.Int("outerDim", 3, "Outer dimension of the matrix")
innerDim = flag.Int("innerDim", 3, "inner dimenstion of the matrix")
limit = flag.Int("limit", 100, "matrix values are limited specified value")
flag.Parse()
randMatrix := make([][]int, *outerDim)
for i := 0; i < *outerDim; i++ {
randMatrix[i] = make([]int, *innerDim)
}
generate(randMatrix)
printMatrix(randMatrix)
}
func generate(randMatrix [][]int) {
for i, innerArray := range randMatrix {
for j := range innerArray {
randMatrix[i][j] = rand.Intn(*limit)
}
}
}
func printMatrix(randMatrix [][]int) {
//looping over 2D slice and extracting 1D slice to val
for _, val := range randMatrix {
fmt.Println(val)// printing each slice
}
}
We could modify the printMatrix function above, by looping over each integer and then formatting it well by using fmt.Printf(), but that would complicate things when we don't known the length of the limit...

iterating over over a 2D slice in go

I am taking the "Tour of Go", and had a question regarding the Exercise: Slices example. Currently I can create the picture by iterating over each index using the the [] operator, just like you could in C.
func Pic(dx, dy int) [][]uint8 {
pic := make([][]uint8, dy)
for i := range pic {
pic[i] = make([]uint8, dx)
for j := range pic[i] {
pic[i][j] = uint8(1)
}
}
return pic
}
However, when I try to do something like below, I get an panic: runtime error: index out of range error. I tried adding print statements and calling Pic(3, 3), which printed out a 3x3 array just fine.
func Pic(dx, dy int) [][]uint8 {
pic := make([][]uint8, dy)
for _, y := range pic {
y = make([]uint8, dx)
for _, x := range y {
x = uint8(1)
_ = x // x has to be used
//fmt.Print("1")
}
//fmt.Print("\n")
}
return pic
}
Any thoughts on what I am doing wrong?
The main problem is your attempt to do assignment. Check my example using your code; https://play.golang.org/p/lwoe79jQ70
What you actually get out of the latter implementation is a 3x0 array, all of the inner arrays are empty. The reason for this is because you're using the range variable for assignment which doesn't work. If the current index is 0, y != pic[0], pic[0] is assigned to y however, y is temporary storage, it typically is the same address and is over written on each iteration. So after the latter example executes, all your x direction arrays are empty, indexing into one causes a panic.
Basically you should just be using your first implementation because it works fine and is the way you would typically do this. But the take away is, when you do a, b := range Something b != Something[a], it is it's on instance, it goes out of scope at the bottom of the loop and assigning to it will not cause a state change to the collection Something, instead you must assign to Something[a] if you want to modify Something[a].
range copies the values from the slice you're iterating over.
See: http://golang.org/ref/spec#RangeClause
To clarify what happens see this simple code example and its output:
package main
import "fmt"
func main() {
s := "hi"
//s[0] = 'H' // cannot assign to s[0]
for _, v := range s {
fmt.Printf("%T, %[1]v, %X\n", v, &v)
v = 'H' // has no effect: this is local var not ref
}
fmt.Println(s)
}
The output is:
int32, 104, C0820042D4
int32, 105, C0820042D4
hi
As you see the address of variable v is not changing (C0820042D4) and v is local variable and range copies value to it, so changing v has no effect.
Here v is rune (int32 alias), A rune is an integer value identifying a Unicode code point, and you cannot assign to s[0] and this won’t compile: s[0] = 'H'
so v = 'H' has no effect on s, it is just local variable.

What is the correct way to find the min between two integers in Go?

I imported the math library in my program, and I was trying to find the minimum of three numbers in the following way:
v1[j+1] = math.Min(v1[j]+1, math.Min(v0[j+1]+1, v0[j]+cost))
where v1 is declared as:
t := "stackoverflow"
v1 := make([]int, len(t)+1)
However, when I run my program I get the following error:
./levenshtein_distance.go:36: cannot use int(v0[j + 1] + 1) (type int) as type float64 in argument to math.Min
I thought it was weird because I have another program where I write
fmt.Println(math.Min(2,3))
and that program outputs 2 without complaining.
so I ended up casting the values as float64, so that math.Min could work:
v1[j+1] = math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost)))
With this approach, I got the following error:
./levenshtein_distance.go:36: cannot use math.Min(int(v1[j] + 1), math.Min(int(v0[j + 1] + 1), int(v0[j] + cost))) (type float64) as type int in assignment
so to get rid of the problem, I just casted the result back to int
I thought this was extremely inefficient and hard to read:
v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
I also wrote a small minInt function, but I think this should be unnecessary because the other programs that make use of math.Min work just fine when taking integers, so I concluded this has to be a problem of my program and not the library per se.
Is there anything that I'm doing terrible wrong?
Here's a program that you can use to reproduce the issues above, line 36 specifically:
package main
import (
"math"
)
func main() {
LevenshteinDistance("stackoverflow", "stackexchange")
}
func LevenshteinDistance(s string, t string) int {
if s == t {
return 0
}
if len(s) == 0 {
return len(t)
}
if len(t) == 0 {
return len(s)
}
v0 := make([]int, len(t)+1)
v1 := make([]int, len(t)+1)
for i := 0; i < len(v0); i++ {
v0[i] = i
}
for i := 0; i < len(s); i++ {
v1[0] = i + 1
for j := 0; j < len(t); j++ {
cost := 0
if s[i] != t[j] {
cost = 1
}
v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
}
for j := 0; j < len(v0); j++ {
v0[j] = v1[j]
}
}
return v1[len(t)]
}
Until Go 1.18 a one-off function was the standard way; for example, the stdlib's sort.go does it near the top of the file:
func min(a, b int) int {
if a < b {
return a
}
return b
}
You might still want or need to use this approach so your code works on Go versions below 1.18!
Starting with Go 1.18, you can write a generic min function which is just as efficient at run time as the hand-coded single-type version, but works with any type with < and > operators:
func min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}
func main() {
fmt.Println(min(1, 2))
fmt.Println(min(1.5, 2.5))
fmt.Println(min("Hello", "世界"))
}
There's been discussion of updating the stdlib to add generic versions of existing functions, but if that happens it won't be until a later version.
math.Min(2, 3) happened to work because numeric constants in Go are untyped. Beware of treating float64s as a universal number type in general, though, since integers above 2^53 will get rounded if converted to float64.
There is no built-in min or max function for integers, but it’s simple to write your own. Thanks to support for variadic functions we can even compare more integers with just one call:
func MinOf(vars ...int) int {
min := vars[0]
for _, i := range vars {
if min > i {
min = i
}
}
return min
}
Usage:
MinOf(3, 9, 6, 2)
Similarly here is the max function:
func MaxOf(vars ...int) int {
max := vars[0]
for _, i := range vars {
if max < i {
max = i
}
}
return max
}
For example,
package main
import "fmt"
func min(x, y int) int {
if x < y {
return x
}
return y
}
func main() {
t := "stackoverflow"
v0 := make([]int, len(t)+1)
v1 := make([]int, len(t)+1)
cost := 1
j := 0
v1[j+1] = min(v1[j]+1, min(v0[j+1]+1, v0[j]+cost))
fmt.Println(v1[j+1])
}
Output:
1
Though the question is quite old, maybe my package imath can be helpful for someone who does not like reinventing a bicycle. There are few functions, finding minimal of two integers: ix.Min (for int), i8.Min (for int8), ux.Min (for uint) and so on. The package can be obtained with go get, imported in your project by URL and functions referred as typeabbreviation.FuncName, for example:
package main
import (
"fmt"
"<Full URL>/go-imath/ix"
)
func main() {
a, b := 45, -42
fmt.Println(ix.Min(a, b)) // Output: -42
}
As the accepted answer states, with the introduction of generics in go 1.18 it's now possible to write a generic function that provides min/max for different numeric types (there is not one built into the language). And with variadic arguments we can support comparing 2 elements or a longer list of elements.
func Min[T constraints.Ordered](args ...T) T {
min := args[0]
for _, x := range args {
if x < min {
min = x
}
}
return min
}
func Max[T constraints.Ordered](args ...T) T {
max := args[0]
for _, x := range args {
if x > max {
max = x
}
}
return max
}
example calls:
Max(1, 2) // 2
Max(4, 5, 3, 1, 2) // 5
Could use https://github.com/pkg/math:
import (
"fmt"
"github.com/pkg/math"
)
func main() {
a, b := 45, -42
fmt.Println(math.Min(a, b)) // Output: -42
}
Since the issue has already been resolved, I would like to add a few words. Always remember that the math package in Golang operates on float64. You can use type conversion to cast int into a float64. Keep in mind to account for type ranges. For example, you cannot fit a float64 into an int16 if the number exceeds the limit for int16 which is 32767. Last but not least, if you convert a float into an int in Golang, the decimal points get truncated without any rounding.
If you want the minimum of a set of N integers you can use (assuming N > 0):
import "sort"
func min(set []int) int {
sort.Slice(set, func(i, j int) bool {
return set[i] < set[j]
})
return set[0]
}
Where the second argument to min function is your less function, that is, the function that decides when an element i of the passed slice is less than an element j
Check it out here in Go Playground: https://go.dev/play/p/lyQYlkwKrsA

Resources