What is the difference between [0] and [:1] in Go? - go

I split a string by spaces:
splstr = strings.Split(str, " ")
Then I iterate each word, and look at the first character like this:
splstr[i][0] == "#"
But I got these errors from that line:
... : cannot convert "#" to type uint8
... : invalid operation: splstr[i][0] == "#" (mismatched types uint8 and string)
But then I spliced it:
splstr[i][:1] == "#"
And that works. I get why [:1] is of type string, but why is [0] of type uint8? (I'm using Go 1.1.)

Because the array notation on a string gives access to the string's bytes, as documented in the language spec:
http://golang.org/ref/spec#String_types
A string's bytes can be accessed by integer indices 0 through len(s)-1.
(byte is an alias for uint8)

[x:x] ([:x] is a form of [0:x]) will cut a slice into another slice while [x] will retrieve the object at index x. The difference is shown below:
arr := "#####"
fmt.Println(arr[:1]) // will print out a string
fmt.Println(arr[0]) // will print out a byte
If the string is converted into []byte:
arr := []byte("#####")
fmt.Println(arr[:1]) // will print out a slice of bytes
fmt.Println(arr[0]) // will print out a byte
You can try this yourself at http://play.golang.org/p/OOZQqXTaYK

Related

when do we use rune function in golang work? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
Improve this question
I am a beginner in Golang...
I found that rune(char) == "-" has been used to check if a character in a word matches with hyphen instead of checking it as char == "-".
Here is the code:
package main
import (
"fmt"
"unicode"
)
func CodelandUsernameValidation(str string) bool {
// code goes here
if len(str) >= 4 && len(str) <= 25 {
if unicode.IsLetter(rune(str[0])) {
for _,char := range str {
if !unicode.IsLetter(rune(char)) && !unicode.IsDigit(rune(char)) && !(rune(char) == '_') {
return false
}
}
return true
}
}
return false;
}
func main() {
// do not modify below here, readline is our function
// that properly reads in the input for you
var user string
fmt.Println("Enter Username")
fmt.Scan(&user)
fmt.Println(CodelandUsernameValidation(user))
}
Could you please clarify why rune is required here?
The code in the question must convert the byte str[0] to a rune for the call to unicode.IsLetter. Otherwise, the rune conversions are not needed.
The required byte to rune conversion hints a problem: The application is treating a byte as a rune, but bytes are not runes.
Fix by using for range to iterate through the runes in the string. This eliminates conversions from the code:
func CodelandUsernameValidation(str string) bool {
if len(str) < 4 || len(str) > 25 {
return false
}
for i, r := range str {
if i == 0 && !unicode.IsLetter(r) {
// str must start with a letter
return false
} else if !unicode.IsLetter(r) && !unicode.IsDigit(r) && !(r == '_') {
// str is restricted to letters, digit and _.
return false
}
}
return true
}
The first thing we need to know is that rune is nothing but an alias of int32. Single quotes represent a rune and double quotes represent a string. so instead of this rune(char) == "-" it should be rune(char) == '-'.
comment from builtin package
// rune is an alias for int32 and is equivalent to int32 in all ways.
It is // used, by convention, to distinguish character values from
integer values.
Second, here we need to know that A loop over the string and accesses it by index returns individual bytes, not characters. like here unicode.IsLetter(rune(str[0])). str[0] returns a byte which is the alias of uint8 not characters. it will fail for some cases because some characters encoded have a length of more than 1 byte because UTF-8. for example take this character ⌘ is represented by the bytes [e2 8c 98] and that those bytes are the UTF-8 encoding, in your example code if you try to access str[0] it will return e2 which may an invalid UTF-8 codepoint or it will represent another character which is a single UTF-8 encoded byte. so here you do like this
strbytes := []byte(str)
firstChar, size := utf8.DecodeRune(strbytes )
A for range loop, by contrast, decodes one UTF-8-encoded rune on each iteration. Each time around the loop, the index of the loop is the starting position of the current rune, measured in bytes, and the code point is its value. so in the example code for _,char := range str { the type of char is rune and again you are trying to convert rune to rune which is duplicated the work.
if want to learn more about strings how they work in Golang here is a great post by Rob Pike
You need to translate from str to []rune
r := []rune(str)
This must be the first line in the function CodelandUsernameValidation.

golang, £ char causing weird  character

I have a function that generates a random string from a string of valid characters. I'm occasionally getting weird results when it selects a £
I've reproduced it to the following minimal example:
func foo() string {
validChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!£$%^&*"
var result strings.Builder
for i := 0; i < len(validChars); i++ {
currChar := validChars[i]
result.WriteString(string(currChar))
}
return result.String()
}
I would expect this to return
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!£$%^&*
But it doesn't, it produces
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!£$%^&*
^
where did you come from ?
if I take the £ sign out of the original validChars string, that weird A goes away.
func foo() string {
validChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!$%^&*"
var result strings.Builder
for i := 0; i < len(validChars); i++ {
currChar := validChars[i]
result.WriteString(string(currChar))
}
return result.String()
}
This produces
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!$%^&*
A string is a type alias for []byte. Your mental model of a string is probably that it consists of a slice of characters - or, as we call it in Go: a slice of rune.
For many runes in your validChars string this is fine, as they are part of the ASCII chars and can therefore be represented in a single byte in UTF-8. However, the £ rune is represented as 2 bytes.
Now if we consider a string £, it consists of 1 rune but 2 bytes. As I've mentioned, a string is really just a []byte. If we grab the first element like you are effectively doing in your sample, we will only get the first of the two bytes that represent £. When you convert it back to a string, it gives you an unexpected rune.
The fix for your problem is to first convert string validChars to a []rune. Then, you can access its individual runes (rather than bytes) by index, and foo will work as expected. You can see it in action in this playground.
Also note that len(validChars) will give you the count of bytes in the string. To get the count of runes, use utf8.RuneCountInString instead.
Finally, here's a blog post from Rob Pike on the subject that you may find interesting.

parenthesis and curly braces difference in golang

a := []byte("H") //works
a := []byte{"H"} //does not compile
What is the conceptual difference between () and {} as used above?
The reason is the difference between type conversions and slice literals.
_ = []byte("Hi!") // Converts a string literal to a []byte.
_ = []byte{'H', 'i', '!'} // Initializes a []byte literal
Your second example []byte{"H"} fails to compile because "H" is a string literal that is being used in place of a rune literal, it's comparable to trying to assign a string to a byte typed variable:
var y byte = 'H' // OK
var x byte = "H" // ERROR: cannot use "H" (type string) as type byte in assignment
In the first one a := []byte("H") you are type casting the string "H" into a byte array.
In the second one a := []byte{"H"} you are defining a byte array and assigning "H" as it's first value, which is invalid.
You can compare the second one with defining a string array:
s := []string{"hello","world",".."} // works
f := []string{1,2,4} // fails because the datatype is wrong

Converting a []byte containing strings into decimal values

I am trying to take a string and convert each value in the string into the decimal ASCII value. I first converted the string into the []byte type and i want to take each element of the []byte and convert it into decimal ASCII value. Here is my code:
myArray := []byte(password) // convert string into []byte type
NumArray := [len(password)]int // create second []int type to store the converted []byte elements
for i := 0; i < len(myArray); i++{
/* I need some help to convert each element in myArray into ASCII decimal value and then store it into
NumArray.
*/
fmt.Printf("%d\n", myArray[i]) //prints out what the converted values should be
fmt.Print(NumArray[i]) //prints out the stored converted value for comparison
}
Edit: the string is supposed to be a password and so can contain any value
You can cast byte to int like this:
NumArray[i] = int(myArray[i])

Dynamically built formatting strings in Golang

I am attempting to create a formatting string dynamically in Go. The idea is that a map is created with the formatting types. Then a loop goes through them to output the various types.
The end result is to see how the formatting affects the output.
(I appreciate the example will produce the same output, but I would change f over time to other types)
Below is an example of this:
import (
"fmt"
"strings"
)
var formats = []string{"%f", "%v"}
var f float32 = 1 << 24
func main() {
for format := range formats {
// Generate formatting string here
parts := "%q => " + format + "\n"
fmt.Printf(parts, format, f)
}
}
The compiler is complaining about a int() conversion at the parts: line:
at line 11, file ch3/floating_point.go cannot convert "%q => " to type int
at line 11, file ch3/floating_point.go invalid operation: "%q => " + format` (mismatched types string and int)
I have attempted joining strings, but no luck:
parts:= strings.Join([]string{"%q =>",format,"\n"), " ")
fmt.Printf(parts,format,f)
Also fmt.Fprintf isn't helping either:
for format := range formats {
// Generate formatting string here
parts := fmt.Fprintf("%q => " + format, format, f)
fmt.Println(parts)
}
The issue is in your for format := range formats construct. Keep in mind that range formats will return two values: the actual value from the slice *and its index (which is the first value). So "%q => " + format + "\n" will actually try to concatenate "%s => " with the numeric iteration index.
If you want to iterate over the values contained in the slice, use the following loop for that:
for _, format := range formats {
// ...
}
See golang For and blank identifier
If you're looping over an array, slice, string, or map, or reading
from a channel, a range clause can manage the loop.
for key, value := range oldMap {
newMap[key] = value
}
Right way to range with array
for index, value := range formats {
if you want to skip index do
for _, value := range formats {

Resources