I was just wondering why these brackets haven't been removed after running go fmt, does their use have a function?
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
{
{
{
}
}
}
}
Example here, thanks.
They basically function like an internal namespace, so any definition(s) you put in between an encapsulating brace will not be visible outside of it.
// ... other code above ...
{
a := 5 // declare a
}
a = 5 // compiler error, a is undeclared
And plus formatting tools such as gofmt or autopep8 (for python) do not modify a given file beyond adding/removing whitespace or newline characters to already existing code.
Brackets on their own denote code Blocks. From the spec:
A block is a possibly empty sequence of declarations and statements within matching brace brackets.
These are part of the Go syntax, and go fmt formats them according the its formatting rules.
Related
This question already has answers here:
What is "_," (underscore comma) in a Go declaration?
(9 answers)
Closed 2 years ago.
I don't understand how to reassign a variable in a block scope appropriately in go.
package main
import (
"fmt"
"path/filepath"
)
func main() {
base := "/a/b/c"
other := "/a/b/c/d/e"
for base != other {
other, file := filepath.Split(other) // "other declared but not used"
fmt.Println(file)
}
}
I want to use both parts of filepath.Split, so I need :=, since file is not declared yet. I want other to get shorter and shorter, so I reassign the result of filepath.Split, but the go compiler doesn't let me run this code.
Why is this the case, and how am I supposed to do this sort of thing?
The body of the loop is an another block, so using short variable declaration in it will not use the other variable declared before, outside of the loop, but will create a new other variable scoped to the body block. Given that, this second other variable is not used anywhere, because the base != other condition in the loop refers to the outer other variable, hence the compile-time error.
Create the expected second variable first, and use simple assignment instead of short variable declaration:
base := "/a/b/c"
other := "/a/b/c/d/e"
for base != other {
var file string
other, file = filepath.Split(other) // "other declared but not used"
fmt.Println(file)
}
Note that the above code will run into an endless loop because filepath.Split() leaves the trailing slash in other, so in the next iteration filepath.Split() will return the same other (the last dir will not be cut off), and won't ever change again.
To make your code do what you want, you have to cut trailing slashes off, like this:
for base != other {
var file string
other, file = filepath.Split(other) // "other declared but not used"
fmt.Println(file)
if strings.HasSuffix(other, "/") {
other = other[:len(other)-1]
}
}
This will now run and output (try it on the Go Playground):
e
d
Note that the same thing could be achieved with a lot simpler code if you'd use filepath.Base() to get the last part of the path, and filepath.Dir() to get the parent folder, like this:
base := "/a/b/c"
other := "/a/b/c/d/e"
for base != other {
fmt.Println(filepath.Base(other))
other = filepath.Dir(other)
}
This outputs the same, try it on the Go Playground.
See related questions:
Why does initializing just one variable in a definition fail, in golang
Why there are two ways of declaring variables in Go, what's the difference and which to use?
How can I invoke a function while using named arguments?
(If it's unclear what named arguments are, here's an example of using them in Python)
Example of what I'd like to do:
func Add(a int, b int) int {
return a + b
}
func main() {
c := Add(a: 1, b:3)
return c
}
However, the above gives me the error:
unexpected :, expecting comma or )
(it's referring to the ':' right after the 'a')
In brief: the Go language does not support named args but IDEs do (see below).
I agree that named arguments could be useful in Go. It could help avoid bugs. For example, just yesterday my tests picked up a bug where the source and dest. parameters to copy() (Go built-in function) were back to front.
However, there are probably hundreds of useful language features that Go could have. We try to avoid adding non-essential features to the language to keep things simple. Once you've used Go for a large project you will greatly appreciate how much simpler things are compared to other languages. (I have used more than a dozen languages professionally and Go is by far the least annoying.)
But actually you can have named arguments if your IDE supports it. For example, I use GoLand and when you enter the arguments to a function it shows the parameter name (in light gray) in-line with a colon before the value. This is even better than what you are used to as you don't even have to type the name!
Go does not have named arguments. The closest thing I know of in Go to named arguments is using a struct as input. So for your example you could do -
type Input struct {
A int
B int
}
func Add(in Input) int {
return in.A + in.B
}
func main() {
c := Add(Input{A: 1, B: 3})
return c
}
Does fmt.Println need to always belong to a function?
Have used Python before and it allows it but on research, it seems that Java doesn't
fmt.Println("can I do it?")
Returns:
syntax error: non-declaration statement outside function body
It may be outside of a function, see this example:
var n, err = fmt.Println("I can do it")
func main() {
fmt.Println("In main(),", n, err)
}
It outputs (try it on the Go Playground):
I can do it
In main(), 12 <nil>
(The output values 12 <nil> are the values returned by the first fmt.Println() call, the number of bytes it has written and the error it returned which is nil indicating no error.)
Also note that you don't even have to store the return values of fmt.Prinln(), you can use the blank identifier like this:
var _, _ = fmt.Println("I can do it")
It cannot stand on its own at the top level "between" top-level declarations, but the above variable declaration (with blank identifier) pretty much achieves the same.
Spec: Source file organization:
Each source file consists of a package clause defining the package to which it belongs, followed by a possibly empty set of import declarations that declare packages whose contents it wishes to use, followed by a possibly empty set of declarations of functions, types, variables, and constants.
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
Obviously a package clause or import declaration can't contain an fmt.Println() call, and the top level declarations:
Declaration = ConstDecl | TypeDecl | VarDecl .
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
A constant declaration cannot contain an fmt.Println() call, that's not a constant expression. A type declaration also cannot contain function calls.
A variable declaration can, as shown in the example at the top of the answer.
Function and method declarations could also call fmt.Println(), but you were asking specifically if fmt.Println() can be called outside of them.
So the only place it is allowed outside of functions that is allowed at the top level is in variable declarations.
go always starts execution in the main function, so fmt.Println() need to be in the main function or a function that is called in main.
So I've been trying to use golang again and I remembered go has a formatting tool to clean up your source. So When I run go fmt on my project the following error gets spit out:
expected declaration, found '{'
I was expecting go fmt to fix my brackets to respect go's syntax requirements, but it just spits out an error. Is this intended functionality or is it supposed to actually put the bracket on the correct line (same line as the function declaration)?
Basic code in question that I was expecting to be properly formatted:
package main
func main()
{
println("Learning go again")
}
Go has some very strong opinions about what a valid code is.
This is one of the cases. Unlike many other C-family languages that allow putting curly bracket of function body declaration on the same line or on the next line (or even ten lines after, if you fancy), Go compiler allows it to be put only on the same line.
Another example is the else statement. Where in other languages
if {
}
else {
}
May be valid or even preferred, in Go only compiling else statement is of the form
if {
} else {
}
The go fmt will fix empty or missing spaces though:
func main() {
fmt.Println("Hello, playground")
}
func main(){
fmt.Println("Hello, playground")
}
Will both become
func main() {
fmt.Println("Hello, playground")
}
I have made a program in Golang and I am trying to use a file as the first argument when launching my program.
For example: ./goprogram.exe C:\Acidic\image.png
When my program tries to use the os.Arg[1] variable which should be the link to the image.png file, it returns the string without any of the backslashes (C:Acidicimage.png).
How can I use the whole string of an argument without characters being escaped?
I have made a little example:
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) >= 2 {
fmt.Println(os.Args[1])
}
}
I run go run args.go C:\Users\image.png and it outputs C:Usersimage.png
Put any argument between quotes:
./goprogram.exe "C:\Acidic\image.png"
The issue appears to be your shell. Try quoting the file path:
./goprogram.exe 'C:\Acidic\image.png' # prevents escape sequence execution
A string fo type C:\Acidic\image.png (with single \'s) is not a valid string in Go (invalid escape sequence \A, etc) and would not even compile.