Strange behavior when appending to a 2d slice - go

I am using a 2D slice of bytes to represent a bunch of lines, but when I append to one of the lines, I get some very strange behavior.
Here is an example:
package main
import (
"bytes"
"fmt"
)
func main() {
str := []byte("first line\nsecond line\nthird line")
values := bytes.Split(str, []byte("\n"))
fmt.Println("Before:")
fmt.Println(string(values[0]))
fmt.Println(string(values[1]))
fmt.Println(string(values[2]))
fmt.Println()
values[0] = append(values[0], []byte("-inserted text-")...)
fmt.Println("After:")
fmt.Println(string(values[0]))
fmt.Println(string(values[1]))
fmt.Println(string(values[2]))
}
I would expect the output of this program to be
Before:
first line
second line
third line
After:
first line-inserted text-
second line
third line
But instead the output is:
Before:
first line
second line
third line
After:
first line-inserted text-
inserted te
t-ird line
https://play.golang.org/p/iNw6s1S66U
Why is this happening and how can I fix it?
Interestingly, this doesn't happen if I don't use split and instead define values like so:
values := [][]byte{[]byte("first line"), []byte("second line"), []byte("third line")}
https://play.golang.org/p/pEflrhKLd4

The underlying storage is shared, so to get the effect you want, you would need to store copies of the slices returned from bytes.Split, rather than just the slices returned. When you append to the first slice returned, you're essentially stomping all over the following slices.

What you're doing is appending to the string, instead of appending to the array and thats overflowing the underlying data structure for the slice. Which is why the rest of the array is overwritten with the string you're appending.
To clarify (this may not always be the case):
the array values consists of 3 []byte blocks lined up consecutively. Each []byte block has a fixed length (based on the length of the string within it). So values[0] has a length of 10 (excluding '\n' or '\0'). Now if you try to append "-inserted text-" to that block, the characters will "flow" over into the consecutive block, values[1], replacing the characters within values[1] with the characters in "-inserted text-". That's why you see parts of those characters within values[1] and values[1].

Related

Golang Typecasting

I have specific questions for my project
input = "3d6"
I want to convert this string some parts to integer. For instance I want to use input[0] like integer.
How can I do this?
There's two problems here:
How to convert a string to an integer
The most straightforward method is the Atoi (ASCII to integer) function in the strconv package., which will take a string of numeric characters and coerce them into an integer for you.
How to extract meaningful components of a known string pattern
In order to use strconv.Atoi, we need the numeric characters of the input by themselves. There's lots of ways to slice and dice a string.
You can just grab the first and last characters directly - input[:1] and input[2:] are the ticket.
You could split the string into two strings on the character "d". Look at the split method, a member of the strings package.
For more complex problems in this space, regular expressions are used. They're a way to define a pattern the computer can look for. For example, the regular expression ^x(\d+)$ will match on any string that starts with the character x and is followed by one or more numeric characters. It will provide direct access to the numeric characters it found by themselves.
Go has first class support for regular expressions via its regexp package.
For example,
package main
import (
"fmt"
)
func main() {
input := "3d6"
i := int(input[0] - '0')
fmt.Println(i)
}
Playground: https://play.golang.org/p/061miKcXdIF
Output:
3

how to split long lines for fmt.sprintf

I have a very long line in fmt.Sprintf. How do I split it in the code? I don't want to put everything in a single line so the code looks ugly.
fmt.Sprintf("a:%s, b:%s ...... this goes really long")
Use string concatenation to construct a single string value on multiple lines:
fmt.Sprintf("a:%s, b:%s " +
" ...... this goes really long",
s1, s2)
The long string in this example is built at compile time because the string concatenation is a constant expression.
You can split the string at contained newlines using a raw string literal:
fmt.Sprintf(`this text is on the first line
and this text is on the second line,
and third`)
You can also use raw string literals inside backticks, like this:
columns := "id, name"
table := "users"
query := fmt.Sprintf(`
SELECT %s
FROM %s
`, columns, table)
fmt.Println(query)
There are a few caveats to this approach:
Raw strings don't parse escape sequences
All the whitespace will be preserved, so there will be a newline and then several tabs before the FROM clause in this query.
These problems can be a challenge for some, and the whitespace will produce some ugly resulting strings. However, I prefer this approach as it allows you to copy and paste long, complex SQL queries outside of your code and into other contexts, like sql worksheets for testing.
Since you're using Sprintf already (meaning you'll have a string like "this is the string with %s placeholders in it") you could just add more place holders to the string and then put the values you'd like there on their own lines like;
fmt.Sprintf("This %s is so long that I need %s%s%s for the other three strings,
"string",
"some super long statement that I don't want to type on 50 lines",
"another one of those",
"yet another one of those")
Another option is just to use string concatenation like "string 1" + "string 2".
Another option is strings.Builder:
package main
import (
"fmt"
"strings"
)
func main() {
b := new(strings.Builder)
fmt.Fprint(b, "North")
fmt.Fprint(b, "South")
println(b.String() == "NorthSouth")
}
https://golang.org/pkg/strings#Builder
Why don't you split it out:
fmt.Sprintf("a:%s, b:%s ", x1, x2)
fmt.Sprintf("...... ")
fmt.Sprintf("this goes really long")
Or you can split them out with the plus sign as indicated by MuffinTop.

How to break a long line of code in Golang?

Coming from Python, I'm not used to see code lines longer than 80 columns.
So when I encounter this:
err := database.QueryRow("select * from users where user_id=?", id).Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)
I tried to break it to
err := database.QueryRow("select * from users where user_id=?", id) \
.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)
But I get
syntax error: unexpected \
I also tried just breaking the line with hitting enter and put a semicolon at the end:
err := database.QueryRow("select * from users where user_id=?", id)
.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email);
But the I again get:
syntax error: unexpected .
So I'm wondering what's the golangic way to do so?
First some background. The formal grammar of Go uses semicolons ";" as terminators in many productions, but Go programs may omit most of them (and they should to have a clearer, easily readable source; gofmt also removes unnecessary semicolons).
The specification lists the exact rules. Spec: Semicolons:
The formal grammar uses semicolons ";" as terminators in a number of productions. Go programs may omit most of these semicolons using the following two rules:
When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is
an identifier
an integer, floating-point, imaginary, rune, or string literal
one of the keywords break, continue, fallthrough, or return
one of the operators and delimiters ++, --, ), ], or }
To allow complex statements to occupy a single line, a semicolon may be omitted before a closing ")" or "}".
So as you can see if you insert a newline character after the parenthesis ), a semicolon ; will be inserted automatically and so the next line will not be treated as the continuation of the previous line. This is what happened in your case, and so the next line starting with .Scan(&ReadUser.ID,... will give you a compile-time error as this standing by itself (without the previous line) is a compile-time error: syntax error: unexpected .
So you may break your line at any point which does not conflict with the rules listed under point 1. above.
Typically you can break your lines after comma ,, after opening parenthesis e.g. (, [, {, and after a dot . which may be referencing a field or method of some value. You can also break your line after binary operators (those that require 2 operands), e.g.:
i := 1 +
2
fmt.Println(i) // Prints 3
One thing worth noting here is that if you have a struct or slice or map literal listing the initial values, and you want to break line after listing the last value, you have to put a mandatory comma , even though this is the last value and no more will follow, e.g.:
s := []int {
1, 2, 3,
4, 5, 6, // Note it ends with a comma
}
This is to conform with the semicolon rules, and also so that you can rearrange and add new lines without having to take care of adding / removing the final comma; e.g. you can simply swap the 2 lines without having to remove and to add a new comma:
s := []int {
4, 5, 6,
1, 2, 3,
}
The same applies when listing arguments to a function call:
fmt.Println("first",
"second",
"third", // Note it ends with a comma
)
The simplest way is to simply leave the operator (.) on the first line.
\ line continuations are also discouraged in many python style guides, you could wrap the whole expression in parens if you are moving back and forth between go and python as this technique works in both languages.
As mentioned, this is a matter of style preference. I understand that the creators of Go have suggested a style based on their experience of which I learn from but also keep some of my own style from my experience.
Below is how I would format this:
err := database.
QueryRow("select * from users where user_id=?", id).
Scan(
&ReadUser.ID,
&ReadUser.Name,
&ReadUser.First,
&ReadUser.Last,
&ReadUser.Email,
)
It's a matter of style, but I like:
err := database.QueryRow(
"select * from users where user_id=?", id,
).Scan(
&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email,
)
what's the golangic way to do so?
An automated solution. Unfortunately, gofmt doesn't cover this case so you could use
https://github.com/segmentio/golines
Install it via
go install github.com/segmentio/golines#latest
Then run
golines -w -m 80 .
-w means make the changes in-place (default prints to stdout)
-m is max column length
You can break the line at several places like commas or braces as suggested by other answers. But Go community has this opinion on line length:
There is no fixed line length for Go source code. If a line feels too long, it should be refactored instead of broken.
There are several guidelines there in the styling guide. I am adding some of the notable ones (clipped):
Commentary
Ensure that commentary is readable from source even on narrow screens.
...
When possible, aim for comments that will read well on an 80-column wide terminal, however this is not a hard cut-off; there is no fixed line length limit for comments in Go.
Indentation confusion
Avoid introducing a line break if it would align the rest of the line with an indented code block. If this is unavoidable, leave a space to separate the code in the block from the wrapped line.
// Bad:
if longCondition1 && longCondition2 &&
// Conditions 3 and 4 have the same indentation as the code within the if.
longCondition3 && longCondition4 {
log.Info("all conditions met")
}
Function formatting
The signature of a function or method declaration should remain on a single line to avoid indentation confusion.
Function argument lists can make some of the longest lines in a Go source file. However, they precede a change in indentation, and therefore it is difficult to break the line in a way that does not make subsequent lines look like part of the function body in a confusing way:
// Bad:
func (r *SomeType) SomeLongFunctionName(foo1, foo2, foo3 string,
foo4, foo5, foo6 int) {
foo7 := bar(foo1)
// ...
}
// Good:
good := foo.Call(long, CallOptions{
Names: list,
Of: of,
The: parameters,
Func: all,
Args: on,
Now: separate,
Visible: lines,
})
// Bad:
bad := foo.Call(
long,
list,
of,
parameters,
all,
on,
separate,
lines,
)
Lines can often be shortened by factoring out local variables.
// Good:
local := helper(some, parameters, here)
good := foo.Call(list, of, parameters, local)
Similarly, function and method calls should not be separated based solely on line length.
// Good:
good := foo.Call(long, list, of, parameters, all, on, one, line)
// Bad:
bad := foo.Call(long, list, of, parameters,
with, arbitrary, line, breaks)
Conditionals and loops
An if statement should not be line broken; multi-line if clauses can lead to indentation confusion.
// Bad:
// The second if statement is aligned with the code within the if block, causing
// indentation confusion.
if db.CurrentStatusIs(db.InTransaction) &&
db.ValuesEqual(db.TransactionKey(), row.Key()) {
return db.Errorf(db.TransactionError, "query failed: row (%v): key does not match transaction key", row)
}
If the short-circuit behavior is not required, the boolean operands can be extracted directly:
// Good:
inTransaction := db.CurrentStatusIs(db.InTransaction)
keysMatch := db.ValuesEqual(db.TransactionKey(), row.Key())
if inTransaction && keysMatch {
return db.Error(db.TransactionError, "query failed: row (%v): key does not match transaction key", row)
}
There may also be other locals that can be extracted, especially if the conditional is already repetitive:
// Good:
uid := user.GetUniqueUserID()
if db.UserIsAdmin(uid) || db.UserHasPermission(uid, perms.ViewServerConfig) || db.UserHasPermission(uid, perms.CreateGroup) {
// ...
}
// Bad:
if db.UserIsAdmin(user.GetUniqueUserID()) || db.UserHasPermission(user.GetUniqueUserID(), perms.ViewServerConfig) || db.UserHasPermission(user.GetUniqueUserID(), perms.CreateGroup) {
// ...
}
switch and case statements should also remain on a single line.
// Good:
switch good := db.TransactionStatus(); good {
case db.TransactionStarting, db.TransactionActive, db.TransactionWaiting:
// ...
case db.TransactionCommitted, db.NoTransaction:
// ...
default:
// ...
}
// Bad:
switch bad := db.TransactionStatus(); bad {
case db.TransactionStarting,
db.TransactionActive,
db.TransactionWaiting:
// ...
case db.TransactionCommitted,
db.NoTransaction:
// ...
default:
// ...
}
If the line is excessively long, indent all cases and separate them with a blank line to avoid indentation confusion:
// Good:
switch db.TransactionStatus() {
case
db.TransactionStarting,
db.TransactionActive,
db.TransactionWaiting,
db.TransactionCommitted:
// ...
case db.NoTransaction:
// ...
default:
// ...
}
Never brake long URLs into multiple lines.
I have only added some of the few examples there are in the styling guide. Please read the guide to get more information.

How to print out non-contiguous sections of the slice in Go?

Wondering if there is a way to print out non contiguous portions of slice in Gol?
Example:
words := []string{"Mary","had","a","little","lamb"}
and I want to print out "Mary" and "lamb" from the slice?
Something along the lines of:
fmt.Printf("%s\n", words[0],[5])
...which obviously this won't work... Is there a way ? :(
Thanks a lot!!
You can index into the slice, you just are doing it wrong.
fmt.Printf("%s %s\n", words[0], words[5])
Your syntax for indexing didn't work because the second variable was just the index stuff without words. Additionally your format string was wrong, a single %s which means Printf is only expecting a single argument after that. Gotta have one formatter per arg.

Why doesn't iterating over each index of a string not function correctly?

I'm trying to perform an operation on each character of a string which is followed by another character, i.e. one that is not the last character. My code is:
[0..(str.length - 2)].each do |index|
// do something with index
end
The code errors out. [0..(str.length - 2)] returns a range object rather than an actual range which can be iterated over. Putting a return index in the body of the above causes a single iteration, with an output of something like [0..7]. Why isn't this iterating over each number?
By enclosing the range in [..], you have created an Array containing a single Range object. In other words, the length of your Array is one. You just want:
(0..(str.length - 2)).each do |index|
// do something with index
end
What you've got there is an array containing a Range rather than a single range, so each is yielding you that one range rather than the integers in that range. Replace the [] with () and you should be ok.
It should be:
(0..(str.length - 2)).each do |index|
// do something with index
end

Resources