I am having a little trouble with what I though was a simple task.
I have a function that formats a struct that holds an hour and a minute value and formats it into a string.
type Clock struct {
h int
m int
}
func (c *Clock) String() string {
h string
m string
if c.m < 10 {
m := fmt.Sprintf("0%d", c.m)
} else {
m := fmt.Sprintf("%d", c.m)
}
if c.h < 10 {
h := fmt.Sprintf("0%d", c.h)
} else {
h := fmt.Sprintf("%d", c.h)
}
return fmt.Sprintf("%s:%s", h, m)
}
The error I am getting is:
syntax error: unexpected name, expecting semicolon or newline or } for the line h string above.
Any idea what is going on here? I figured I would simple use a temporary variable to format the int values
You need to declare:
var h string
var m string
And do not use := but = when affecting values to h and m (or you would define those only in their inner scope, instead of reusing the variables defined before)
if c.m < 10 {
m = fmt.Sprintf("0%d", c.m)
} else {
m = fmt.Sprintf("%d", c.m)
}
if c.h < 10 {
h = fmt.Sprintf("0%d", c.h)
} else {
h = fmt.Sprintf("%d", c.h)
}
Full example: play.golang.org
Output: Hello, playground 02:08
Declare the String method variables once (var). Do not redeclare them with short variable declarations (:=). For example,
package main
import "fmt"
type Clock struct {
h int
m int
}
func (c *Clock) String() string {
var (
h string
m string
)
if c.m < 10 {
m = fmt.Sprintf("0%d", c.m)
} else {
m = fmt.Sprintf("%d", c.m)
}
if c.h < 10 {
h = fmt.Sprintf("0%d", c.h)
} else {
h = fmt.Sprintf("%d", c.h)
}
return fmt.Sprintf("%s:%s", h, m)
}
func main() {}
References:
The Go Programming Language Specification
Declarations and scope
Type declarations
Variable declarations
Short variable declarations
Related
I'd like to catch panic: runtime error: index out of range in the following loop (inside function without returning) and concat X for each panic: runtime error: index out of range to the result:
func transform(inputString string, inputLength int) string {
var result = ""
for index := 0; index < inputLength; index++ {
if string(inputString[index]) == " " {
result = result + "%20"
} else {
result = result + string(inputString[index])
}
}
return result
}
for example for inputString = Mr Smith and inputLength = 10 the result is Mr%20SmithXX. It has two X because 10 - 8 = 2.
I know I can catch the panic in returning from transform() but I'd like to handle it inside the loop without returning the function.
inputString = Mr Smith and inputLength = 10 the result is Mr%20SmithXX. It has two X because 10 - 8 = 2.
package main
import "fmt"
func transform(s string, tLen int) string {
t := make([]byte, 0, 2*tLen)
for _, b := range []byte(s) {
if b == ' ' {
t = append(t, "%20"...)
} else {
t = append(t, b)
}
}
for x := tLen - len(s); x > 0; x-- {
t = append(t, 'X')
}
return string(t)
}
func main() {
s := "Mr Smith"
tLen := 10
fmt.Printf("%q %d\n", s, tLen)
t := transform(s, tLen)
fmt.Printf("%q\n", t)
}
https://go.dev/play/p/wg7MIO8yUzF
"Mr Smith" 10
"Mr%20SmithXX"
This question already has answers here:
How to assign or return generic T that is constrained by union?
(2 answers)
Closed 10 months ago.
The following fails to compile on line res = fmt.Sprintf("%s + %s", i, j) with the error: cannot use fmt.Sprintf("%s + %s", i, j) (value of type string) as type T in assignment
It does allow me to return an int and the code does compile and run if I simply return i + j.
I'm missing some fundamental understanding and need to be pointed in the correct direction.
import (
"fmt"
"reflect"
)
type Adder interface {
string | int
}
func Add[T Adder](i, j T) T {
var res T
switch reflect.TypeOf(i).Name() {
case "int":
res = i + j
case "string":
res = fmt.Sprintf("%s + %s", i, j)
}
return res
}
func main() {
it := Add(3, 4)
st := Add("one", "two")
fmt.Println("Int:", it)
fmt.Println("Str:", st)
}
Take a look at what Add does for strings:
func Add[string](i, j string) string {
var res string
switch reflect.TypeOf(i).Name() {
case "int":
res = i + j
case "string":
res = fmt.Sprintf("%s + %s", i, j)
}
return res
}
This is ok. The expression i + j just concatenates two strings. Take a look at what Add does for int:
func Add[int](i, j int) int {
var res int
switch reflect.TypeOf(i).Name() {
case "int":
res = i + j
case "string":
res = fmt.Sprintf("%s + %s", i, j)
}
return res
}
This is a type error. It does not matter that the "string" branch is never taken at runtime—the entire function must typecheck!
(Note that Go does not actually instantiate generics by inserting the types—but you get the idea.)
The body of the generic function must be valid for all possible types. If res is int, the "string" case cannot be compiled. If res is string, both cases are valid expressions.
You can try this idea by declaring
type Adder interface {
string
}
and making the necessary changes. You still need to:
res = T(fmt.Sprintf("%s + %s", i, j))
I am writing out a homework problem which I may have over-engineered with too many structs. It made sense at the time. I want to loop through Seasonal Discounts (through 2 different arrays- HighPrices, and LowPrices ) and just not sure if a) the set up is good or not, b) how to add the price in a less redundant manner.
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(getPrice(2, "bananas"))
}
func getPrice(p float32, f string) float32 {
type HighPriceItems struct {
items []string
price float32
}
type LowPriceItems struct {
items []string
price float32
}
type seasonMatrix struct {
h HighPriceItems
l LowPriceItems
}
var seasonPrices = func() seasonMatrix {
var h = HighPriceItems{}
var l = LowPriceItems{}
var season = seasonMatrix{}
switch time.Now().Month() {
case time.March, time.April, time.May, time.June, time.July:
h := append(h.items, "apples", "oranges", "pears")
l := append(l.items, "bananas", "grapes")
season.h.items = h
season.h.price = 4
season.l.items = l
season.l.price = 2
return season
case time.August, time.September, time.October, time.November, time.December, time.January, time.February:
h := append(h.items, "bananas", "grapes")
l := append(l.items, "apples", "oranges", "pears")
season.h.items = h
season.h.price = 4
season.l.price = 2
season.l.items = l
return season
}
return season
}
const normalDiscount float32 = .75
var x = p * normalDiscount
var specials = seasonPrices()
var finalPrice float32
for _, n := range specials.h.items {
if f == n {
if specials.h.price > x {
finalPrice = specials.h.price
} else {
finalPrice = x
}
}
}
for _, n := range specials.l.items {
if f == n {
if specials.l.price > x {
finalPrice = specials.l.price
} else {
finalPrice = x
}
}
}
return finalPrice
}
There's no reason for HighPriceItem and LowPriceItem types.
If you make it a single PriceItems, you'll be able to turn the 2 for loops at the end into a function over PriceItems and get rid of the duplicate code inside second for loop.
Also in Go var specials = seasonPrices() is typically written as specials := seasonPrices()
I need to convert an int32 to string in Golang. Is it possible to convert int32 to string in Golang without converting to int or int64 first?
Itoa needs an int. FormatInt needs an int64.
One line answer is fmt.Sprint(i).
Anyway there are many conversions, even inside standard library function like fmt.Sprint(i), so you have some options (try The Go Playground):
1- You may write your conversion function (Fastest):
func String(n int32) string {
buf := [11]byte{}
pos := len(buf)
i := int64(n)
signed := i < 0
if signed {
i = -i
}
for {
pos--
buf[pos], i = '0'+byte(i%10), i/10
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
2- You may use fmt.Sprint(i) (Slow)
See inside:
// Sprint formats using the default formats for its operands and returns the resulting string.
// Spaces are added between operands when neither is a string.
func Sprint(a ...interface{}) string {
p := newPrinter()
p.doPrint(a)
s := string(p.buf)
p.free()
return s
}
3- You may use strconv.Itoa(int(i)) (Fast)
See inside:
// Itoa is shorthand for FormatInt(int64(i), 10).
func Itoa(i int) string {
return FormatInt(int64(i), 10)
}
4- You may use strconv.FormatInt(int64(i), 10) (Faster)
See inside:
// FormatInt returns the string representation of i in the given base,
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatInt(i int64, base int) string {
_, s := formatBits(nil, uint64(i), base, i < 0, false)
return s
}
Comparison & Benchmark (with 50000000 iterations):
s = String(i) takes: 5.5923198s
s = String2(i) takes: 5.5923199s
s = strconv.FormatInt(int64(i), 10) takes: 5.9133382s
s = strconv.Itoa(int(i)) takes: 5.9763418s
s = fmt.Sprint(i) takes: 13.5697761s
Code:
package main
import (
"fmt"
//"strconv"
"time"
)
func main() {
var s string
i := int32(-2147483648)
t := time.Now()
for j := 0; j < 50000000; j++ {
s = String(i) //5.5923198s
//s = String2(i) //5.5923199s
//s = strconv.FormatInt(int64(i), 10) // 5.9133382s
//s = strconv.Itoa(int(i)) //5.9763418s
//s = fmt.Sprint(i) // 13.5697761s
}
fmt.Println(time.Since(t))
fmt.Println(s)
}
func String(n int32) string {
buf := [11]byte{}
pos := len(buf)
i := int64(n)
signed := i < 0
if signed {
i = -i
}
for {
pos--
buf[pos], i = '0'+byte(i%10), i/10
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
func String2(n int32) string {
buf := [11]byte{}
pos := len(buf)
i, q := int64(n), int64(0)
signed := i < 0
if signed {
i = -i
}
for {
pos--
q = i / 10
buf[pos], i = '0'+byte(i-10*q), q
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
The Sprint function converts a given value to string.
package main
import (
"fmt"
)
func main() {
var sampleInt int32 = 1
sampleString := fmt.Sprint(sampleInt)
fmt.Printf("%+V %+V\n", sampleInt, sampleString)
}
// %!V(int32=+1) %!V(string=1)
See this example.
Use a conversion and strconv.FormatInt to format int32 values as a string. The conversion has zero cost on most platforms.
s := strconv.FormatInt(int64(n), 10)
If you have many calls like this, consider writing a helper function similar to strconv.Itoa:
func formatInt32(n int32) string {
return strconv.FormatInt(int64(n), 10)
}
All of the low-level integer formatting code in the standard library works with int64 values. Any answer to this question using formatting code in the standard library (fmt package included) requires a conversion to int64 somewhere. The only way to avoid the conversion is to write formatting function from scratch, but there's little point in doing that.
func FormatInt32(value int32) string {
return fmt.Sprintf("%d", value)
}
Does this work?
I'm trying to write a function that returns the finds first character in a String that doesn't repeat, so far I have this:
package main
import (
"fmt"
"strings"
)
func check(s string) string {
ss := strings.Split(s, "")
smap := map[string]int{}
for i := 0; i < len(ss); i++ {
(smap[ss[i]])++
}
for k, v := range smap {
if v == 1 {
return k
}
}
return ""
}
func main() {
fmt.Println(check("nebuchadnezzer"))
}
Unfortunately in Go when you iterate a map there's no guarantee of the order so every time I run the code I get a different value, any pointers?
Using a map and 2 loops :
play
func check(s string) string {
m := make(map[rune]uint, len(s)) //preallocate the map size
for _, r := range s {
m[r]++
}
for _, r := range s {
if m[r] == 1 {
return string(r)
}
}
return ""
}
The benfit of this is using just 2 loops vs multiple loops if you're using strings.ContainsRune, strings.IndexRune (each function will have inner loops in them).
Efficient (in time and memory) algorithms for grabbing all or the first unique byte http://play.golang.org/p/ZGFepvEXFT:
func FirstUniqueByte(s string) (b byte, ok bool) {
occur := [256]byte{}
order := make([]byte, 0, 256)
for i := 0; i < len(s); i++ {
b = s[i]
switch occur[b] {
case 0:
occur[b] = 1
order = append(order, b)
case 1:
occur[b] = 2
}
}
for _, b = range order {
if occur[b] == 1 {
return b, true
}
}
return 0, false
}
As a bonus, the above function should never generate any garbage. Note that I changed your function signature to be a more idiomatic way to express what you're describing. If you need a func(string) string signature anyway, then the point is moot.
That can certainly be optimized, but one solution (which isn't using map) would be:
(playground example)
func check(s string) string {
unique := ""
for pos, c := range s {
if strings.ContainsRune(unique, c) {
unique = strings.Replace(unique, string(c), "", -1)
} else if strings.IndexRune(s, c) == pos {
unique = unique + string(c)
}
}
fmt.Println("All unique characters found: ", unique)
if len(unique) > 0 {
_, size := utf8.DecodeRuneInString(unique)
return unique[:size]
}
return ""
}
This is after the question "Find the first un-repeated character in a string"
krait suggested below that the function should:
return a string containing the first full rune, not just the first byte of the utf8 encoding of the first rune.