"Declared but not used" variable in for's condition expression [closed] - go

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
My intuitive approach:
https://play.golang.org/p/6xzg7TK1IH
and it doesn't work.
Can you share some alternative ways?

You are declaring a variable (moreline) which you don't use it. You have two options here: either to replace the moreline with underscore, which means you can omit the return value.
for moreline {
line, _, err := bio.ReadLine()
if err != nil {
log.Fatal(err)
}
fmt.Println(line)
}
But a better option will be to use the ReadScanner, ReadBytes('\n') or ReadString('\n').
Checking the bufio.go file this is what you get as description for the ReadLine method:
ReadLine is a low-level line-reading primitive. Most callers should
use ReadBytes('\n') or ReadString('\n') instead or use a Scanner.
Calling UnreadByte after ReadLine will always unread the last byte read (possibly a character belonging to the line end) even if that byte is not part of the line returned by ReadLine. ReadLine either returns a non-nil line or it returns an error, never both.
So this would be a better option:
scanner := bufio.NewScanner(bio)
for scanner.Scan() {
line := scanner.Text()
fmt.Printf("%v\n", line)
}

You use := which discards the previous contents of the variables. You don't use morelines in that scope, thus the error message.
If you declare your variables beforehand and don't use :=, it works fine. The function ReadLine() might not do what you think it should do.
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
bio := bufio.NewReader(os.Stdin)
var line []byte
var err error
moreline := true
for moreline {
line, moreline, err = bio.ReadLine()
if err != nil {
log.Fatal(err)
}
fmt.Println(line)
}
}

Related

How can I scan a rune?

So far, I haven't been able to print a rune by scanning it with fmt.Scan and printing it with fmt.Print. This is the vary basic code I'm working on:
package main
import "fmt"
func main() {
var c rune
fmt.Scan(&c)
fmt.Printf("%c", c)
}
But it doesn't work, in fact, Printf doesn't produce any output. Instead, by manually assigning a char to my variable c (like var c rune = 'a', without using fmt.Scan), I'm able to print the wanted rune. How can I scan a rune?
As we know Scan return n and err so please check for error under Scan statement as follows
n, err := fmt.Scan(&c)
if err != nil {
fmt.Println(err)
}
It will clearly show you the error and why it was ignored.
Other than the above, please try it locally on your own laptop instead of the playground because on the playground it most of the time gives an EOF error as most of them do not support reading from the terminal.
I hope the above helps you in debugging the issue.
Other Reference:
Scanf ignores if not provided \n

Declare mutiple variables on the same line with types in Go

I have the below code snippet:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
var reader *bufio.Reader = bufio.NewReader(os.Stdin)
fmt.Println("Enter your name")
name, err := reader.ReadString('\n') //THIS LINE
if err == nil {
fmt.Println("Hello " + name)
}
}
My question is, if I want to NOT use the := syntax (like I have at the first line of main()), how would I rewrite the ReadString() invocation with types?
I tried the following, with the corresponding errors:
var name string, err error = reader.ReadString('\n') -> syntax error: unexpected comma at end of statement
var name, err string, error = reader.ReadString('\n') -> syntax error: unexpected comma at end of statement
Taking a hint from Multiple variables of different types in one line in Go (without short variable declaration syntax) I also tried var (name string, err error) = reader.ReadString('\n') which also gives the same error.
For the above linked question, the marked answer simply suggests using two lines for two different variable types. But how would that work for the return values of a function like ReadString()?
First of all,
name, err := reader.ReadString('\n')`
is perfectly fine. Most IDE's will display you the types of the return values of ReadString() if you would not know them.
As the linked answer details, a variable declaration can have one optional type at most, so specifying 2 types is not possible.
If it bothers you that the types are not visible, that means readability is more important to you. If it is, break with that "one-liners-for-the-win" philosophy.
If you want the types to be visible in the source code, declare the types prior, and use assignment:
var (
name string
err error
)
name, err = reader.ReadString('\n')
If you still need a one liner (just for fun), it requires a helper function. The name of the helper function can "state" the expected types:
func stringAndError(s string, err error) (string, error) {
return s, err
}
Then you can use either a variable declaration or a short variable declaration:
var name, err = stringAndError(reader.ReadString('\n'))
// OR
name, err := stringAndError(reader.ReadString('\n'))

To what extent are errors strings guaranteed to not change?

One of the main issues I have with Golang is that the error handling is basically a check for a string (I would love to be wrong, do not hesitate :))
In the example below, I am trying to create a directory, but will have different behaviour depending on the kind of issue. Specifically, if a directory exists I will just pass.
package main
import (
"fmt"
"os"
)
func main() {
err := os.Mkdir("test", 0644)
if err != nil {
fmt.Printf("error: %v", err)
if err.Error() == "mkdir test: Cannot create a file when that file already exists" {
fmt.Printf("the dir already exists")
} else {
panic(err)
}
}
}
It does not work, repeated attempts are not logged. Why? Ah, crap, I forgot the dot at the end of the mkdir test: Cannot create a file when that file already exists string.
I feel that relying on an error string is fragile, as opposed to having something like err.ErrorType().DirectoryExists() kind of check (which sometimes exists, in net for instance).
My question: to what extent can I rely on the fact that the error strings will not change? (in other words, that mkdir test: Cannot create a file when that file already exists. will not be worded differently, or ported to another national language, etc.)
I had some hope with errors.Is() but it ultimately relies on the string comparison.
Go error strings don't change arbitrarily, but they also aren't covered by the Go compatibility policy: they can be changed if the increase in clarity outweighs the (inevitable) cost of breaking programs that make (fragile, unsupported) assumptions about the string contents.
The errors package is the robust way to check for specific types of errors.
Use errors.Is to check for equivalence to a canonical error (https://play.golang.org/p/co6ukgQrr58):
err := os.Mkdir(dir, 0644)
if errors.Is(err, os.ErrExist) {
t.Logf("the dir already exists")
} else if err != nil {
t.Fatal(err)
}
Use errors.As to check for a particular type of error (https://play.golang.org/p/UR1nUCRMUY6):
err := os.Mkdir(dir, 0644)
var pe *os.PathError
if errors.As(err, &pe) {
t.Logf("error creating %q: %v", pe.Path, pe.Err)
} else if err != nil {
t.Fatal(err)
}
In this case, you can use os.IsExist(err)
err := os.Mkdir("test", 0644)
if err != nil {
if os.IsExist(err){
fmt.Printf("the dir already exists")
} else {
panic(err)
}
}
Good libraries should allow you to inspect errors without relying on string comparison. Various methods exist to do so:
Comparaison with sentinel values if err == os.EOF
Utility function: os.IsExist(err)
Type assertion: pathErr := err.(*os.PathError)
There is always a way to inspect errors in the standard library without relying on strings. Check the function/package documentation for details about how to do it.
Note:
errors.Is() and errors.As() are a (~recent) generalisation of == and type assertion but for errors that could contain other errors. See https://go.dev/blog/go1.13-errors
From https://pkg.go.dev/os#Mkdir:
Mkdir creates a new directory with the specified name and permission bits (before umask). If there is an error, it will be of type *PathError.
This means you could type-assert the returned error to get more information.
if err != nil {
pathErr := err.(*os.PathError)
}
With errors returned from functions in package os specifically, also take note of these two functions:
https://pkg.go.dev/os#IsExist
https://pkg.go.dev/os#IsNotExist
to what extent can I rely on the fact that the error strings will not change?
To the extent which is guaranteed by the function's contract, which as in most programming languages conventionally is written in documenting comments above the function. In the case of os.MkDir(): you cannot.

Automatically add New Line(s) after 80th character in a string containing ANSI Escape Codes [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I want a Go program to display a CP437-encoded 'ANSI art file', 80 columns wide, that contains ANSI escape codes -- color, cursor placement, etc. and extended ANSI (CP437) box drawing codes.
When viewing the ANSI file in a linux terminal (see Playground link below) with a 80 col CP437-capable terminal, the file displays properly, e.g. line breaks are implicitly read; however, when viewing with a wider terminal (which is the goal), new lines are not implicitly processed/added and the file may display improperly, without required line breaks.
How do I iterate through the .ans file and manually add new lines after the 80th character, counting only the actual characters displayed (not the escape codes)?
I've tried go libraries like ansiwrap and reflow. Ansiwrap is really just for text wrapping, but Reflow gets the closest to the goal, but the line breaks are not quite right.
Playground link of my test code with Reflow.
How it renders (in a CP437 terminal, 132x37):
How it should look (from art program):
To solve this, first I pulled visualLength function from the
golang.org/x/term package [1], then I wrote a bufio.SplitFunc [2] for this
use case.
package main
func ansi(data []byte, eof bool) (int, []byte, error) {
var s []rune
for i, r := range string(data) {
if s = append(s, r); visualLength(s) == 80 {
width := len(string(r))
return i+width, data[:i+width], nil
}
}
return 0, nil, nil
}
Result:
package main
import (
"bufio"
"golang.org/x/text/encoding/charmap"
"os"
)
func main() {
f, err := os.Open("LDA-PHASE90.ANS")
if err != nil {
panic(err)
}
defer f.Close()
s := bufio.NewScanner(charmap.CodePage437.NewDecoder().Reader(f))
s.Split(ansi)
for s.Scan() {
println(s.Text())
}
}
https://github.com/golang/term/blob/6886f2df/terminal.go#L431-L450
https://golang.org/pkg/bufio#SplitFunc

Golang r.URL.Query("x") does not return the full value with special characters [duplicate]

This question already has answers here:
Characters allowed in GET parameter
(7 answers)
Closed 9 months ago.
I was using r.URL.Query("model") to retrieve a url param. Lets say "https://example.com?model=345;1"
My expected behaviour is to retrieve: 345;1
But I only receive: 345
Is there a specific meaning behind it? and how i can force to get the full value. I am quite new go.
Code example
As LeGEC indicated the problem is due the fact that the semi-colon (;) is a character that has (or could have) special meaning in URLs.
You can use "%#v" in your Go Printf example to see how Go parsed the query string:
package main
import "fmt"
import "net/url"
import "log"
func main() {
u, err := url.Parse("https://example.com?model=345;1")
if err != nil {
log.Fatal(err)
}
q := u.Query()
fmt.Printf("%#v",q)
}
Gives
url.Values{"1":[]string{""}, "model":[]string{"345"}}
You could use u.RawQuery to get the entire string "model=345;1" and then parse it yourself. Not ideal, but perhaps a quick workaround.

Resources