Is it possible to do a conversion after assignment? - go

I'm wondering if there is any trick to avoid the xv identifier/allocation. Basically something like x, err := T1(strconv.Atoi("1"))
package main
import "fmt"
import "strconv"
type T1 int
func main() {
xv, err := strconv.Atoi("1")
if err != nil {
panic(err)
}
x := T1(xv)
fmt.Println(x)
}

For example, only x escapes to heap,
package main
import (
"fmt"
"strconv"
)
type T1 int
func atoi(a string) int {
i, err := strconv.Atoi(a)
if err != nil {
panic(err)
}
return i
}
func main() {
x := T1(atoi("1"))
fmt.Println(x)
}
Output:
1

No, I believe there is no such trick.
When I want to avoid declarations of unnecessary variables in the scope, and for one-off operations, I sometimes use this kind of anonymous function calls:
package main
import "fmt"
import "strconv"
type T1 int
func main() {
x, err := func() (T1, error) {
x, err := strconv.Atoi("1")
return T1(x), err
}()
fmt.Println(err, x)
}
On the other hand, if you need to perform a similar cast on many occasions, and not necessarily always as a result of the same call (like Atoi), you could create a simple function, which would do the conversion and pass through the error:
package main
import "fmt"
import "strconv"
type T1 int
func resToT1(n int, err error) (T1, error) {
return T1(n), err
}
func main() {
x, err := resToT1(strconv.Atoi("1"))
fmt.Println(err, x)
}

Related

Different result when run io.Copy(os.Stdout, &r) consecutively in Golang

I am playing around Golang. About io.Copy
I put 2 consecutive io.Copy in the code, but i expect it output twice result(testtesttest). But the 2nd one is nil. Can anyone help explain why? tks
package main
import (
"io"
"os"
"strings"
"fmt"
)
type testReader struct {
w io.Reader
str string
}
func (tt *testReader) Read (b []byte) (n int, err error) {
io.Copy(os.Stdout, tt.w)
n, err = tt.w.Read(b)
if tt.w !=nil {
return 0,io.EOF
}
return
}
func main() {
s := strings.NewReader("testtesttest!!!")
r := testReader{s,"ttthhh"}
fmt.Println(&r)
io.Copy(os.Stdout, &r)
// s.Seek(0,0) // solution from Poy's answer
io.Copy(os.Stdout, &r)
}
I'm going to prune down the given example to (as there is a bit of noise):
package main
import (
"io"
"os"
"strings"
)
func main() {
s := strings.NewReader("testtesttest")
io.Copy(os.Stdout, s) // Will print "testtesttest"
io.Copy(os.Stdout, s) // Won't print anything
}
The reason the second copy won't output anything is the io.Reader (s) has already been read. Reading from a io.Reader is not idempotent (you can't call it twice to get the same results). It also doesn't have a way to "reset" it or anything.
As #JRLambert pointed out you have s.Seek() and s.Reset() to allow you to start reading again.
Quick addition to all the correct answers (#poy and #JRLambert) provided so far... Use io.TeeReader or io.MultiWriter for times when you would want to use io.Copy more than once. Below are some examples of using each.
Using io.TeeReader
package main
import (
"bytes"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
)
func main() {
sourceFile, _ := os.Open("source/ebook.pdf")
var buf bytes.Buffer
tee := io.TeeReader(sourceFile, &buf)
process := func(sourceReader io.Reader) {
targetFile, _ := os.Create("target/ebook.pdf")
defer targetFile.Close()
if _, err := io.Copy(targetFile, sourceReader); err != nil {
fmt.Println(err)
}
}
process(tee)
fmt.Println(checksum(&buf))
}
func checksum(buf *bytes.Buffer) string {
h := md5.New()
b, _ := ioutil.ReadAll(buf)
if _, err := h.Write(b); err != nil {
fmt.Println(err)
}
return hex.EncodeToString(h.Sum(nil)[:16])
}
Using io.MultiWriter
package main
import (
"bytes"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
)
func main() {
sourceFile, _ := os.Open("source/ebook.pdf")
process := func(sourceReader io.Reader) {
targetFile, _ := os.Create("target/ebook.pdf")
defer targetFile.Close()
var buf1, buf2 bytes.Buffer
w := io.MultiWriter(targetFile, &buf1, &buf2)
if _, err := io.Copy(w, sourceReader); err != nil {
fmt.Println(err)
}
fmt.Println(checksum(&buf1))
fmt.Println(checksum(&buf2))
}
process(sourceFile)
}
func checksum(buf *bytes.Buffer) string {
h := md5.New()
b, _ := ioutil.ReadAll(buf)
if _, err := h.Write(b); err != nil {
fmt.Println(err)
}
return hex.EncodeToString(h.Sum(nil)[:16])
}

Mocking functions called from within another in golang

I am trying to stub os.Stat and ioutil.ReadFile(path) as used the code below or if you like here on go playground [1]
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func AssignFileValueFrom(path string, val *string) {
var (
tempValue []byte
err error
)
if _, err = os.Stat(path); err == nil {
if err != nil {
fmt.Println("There was a os stat error:", err)
}
tempValue, err = ioutil.ReadFile(path)
if err != nil {
fmt.Println("There was an io read error:", err)
}
*val = strings.TrimSpace(string(tempValue))
}
}
I have used testify and tried following the example here [2]
package main
import (
"testing"
"github.com/stretchr/testify/mock"
)
type osMock struct {
mock.Mock
}
func (o osMock) Stat(path string) (interface{}, error) {
return nil, nil
}
func TestAssignFileValueFrom(t *testing.T) {
var test string
osm := new(osMock)
osm.On(`Stat`, `./.test`).Return([]byte(`1`), nil)
AssignFileValueFrom(`./.test`, &test)
// assert.Equal(t, `1`, test)
osm.AssertExpectations(t)
}
What am I not doing correctly??
[1] https://play.golang.org/p/xcbdMkMwoBN
[2] https://github.com/stretchr/testify#mock-package
Your code with osMock doesn't any how influence execution of AssignFileValueFrom function. There is a direct call of os.Stat and it won't be substituted just because you have declared osMock somewhere.
To do actual testing you should use interfaces and dependency injection to be able to test your code.
First of all os.Stat call must be substituted with call to your struct that implements an interface with same method defined. And you need to create at least 2 implementations of this interface: 1 - is actual working code to use, 2 - mock as your osMock struct to use in test. And you need to inject it or pass it to AssignFileValueFrom and then use to call Stat method on it.
Thanks, guys for your inputs I have rewritten my tests as follows..
package main
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
var (
err error
testFile *os.File
test string
)
const (
TestPrefix = `test_file_prefix`
FileContent = `1234`
)
func init() {
testFile, err = ioutil.TempFile(os.TempDir(), TestPrefix)
if err != nil {
panic(err)
}
err = ioutil.WriteFile(testFile.Name(), []byte(FileContent), 0644)
if err != nil {
panic(err)
}
}
func TestAssignFileValueFrom(t *testing.T) {
AssignFileValueFrom(testFile.Name(), &test)
assert.Equal(t, test, FileContent)
}

In Go, can JSON marshaling of a well-defined type ever fail?

Given the following code:
package main
import (
"encoding/json"
"fmt"
"log"
)
type Employee struct {
Id int "json:id"
}
func main() {
b, err := json.Marshal(&Employee{Id: 2})
if err != nil {
log.Fatal("Couldn't marshal the Employee")
}
fmt.Println(string(b))
}
Can checking for the error be reliably ignored using the _ placeholder since the Employee struct is well defined. Theoretically it should never fail, so begs the question is it a good practice to ignore this type of error and save a little on this type of boilerplate error checking?
Ignoring would look like so:
package main
import (
"encoding/json"
"fmt"
)
type Employee struct {
Id int "json:id"
}
func main() {
b, _ := json.Marshal(&Employee{Id: 2})
fmt.Println(string(b))
}
Error handling and Go:
Proper error handling is an essential requirement of good software.
Normally your code won't fail. but if user Adds this MarshalJSON method reciver to your type, it fails:
func (t *Employee) MarshalJSON() ([]byte, error) {
if t.Id == 2 {
return nil, fmt.Errorf("Forbiden Id = %d", t.Id)
}
data := []byte(fmt.Sprintf(`{"Id":%d}`, t.Id))
return data, nil
}
This code Compiles, but fails on purpose just for Id == 2 (The Go Playground):
package main
import (
"encoding/json"
"fmt"
"log"
)
type Employee struct {
Id int "json:id"
}
func main() {
b, err := json.Marshal(&Employee{Id: 2})
if err != nil {
log.Fatal("Couldn't marshal the Employee", err)
}
fmt.Println(string(b))
}
func (t *Employee) MarshalJSON() ([]byte, error) {
if t.Id == 2 {
return nil, fmt.Errorf("Forbiden Id = %d", t.Id)
}
data := []byte(fmt.Sprintf(`{"Id":%d}`, t.Id))
return data, nil
}
Also this code Compiles, but fails (The Go Playground):
package main
import (
"encoding/json"
"fmt"
"log"
)
type Employee struct {
Id int "json:id"
}
func main() {
b, err := json.Marshal(&Employee{Id: 2})
if err != nil {
log.Fatal("Couldn't marshal the Employee")
}
fmt.Println(string(b))
}
func (t Employee) MarshalJSON() ([]byte, error) {
data := []byte(fmt.Sprint(t))
return data, nil
}
You can always write your own "wrapper" packages to compose behavior that might otherwise be boilerplate. For example, if you have a logging system set up, you might build a small package that looks like:
package json
import (
"encoding/json"
"log"
)
func TryMarshal(v interface{}) []byte {
b, err := json.Marshal(v)
if err != nil {
log.Println(err)
return nil
}
return b
}

Save an image from url to file

Very new to Go (first simple project I'm working on).
Question: How do I get an image from URL and then save it to my computer?
Here's what I have so far:
package main
import (
"fmt"
"net/http"
"image"
"io/ioutil"
)
func main() {
url := "http://i.imgur.com/m1UIjW1.jpg"
// don't worry about errors
response, _ := http.Get(url);
defer response.Body.Close()
m, _, err := image.Decode(response.Body)
error := ioutil.WriteFile("/images/asdf.jpg", m, 0644)
}
However, when I run this code, I get cannot use m (type image.Image) as type []byte in function argument
I'm assuming I have to convert image.Image (variable m) into an undefined amount of bytes? Is that the correct way to go about this?
There is no need to decode the file. Simply copy the response body to a file you've opened. Here's the deal in the modified example:
response.Body is a stream of data, and implements the Reader interface - meaning you can sequentially call Read on it, as if it was an open file.
The file I'm opening here implements the Writer interface. This is the opposite - it's a stream you can call Write on.
io.Copy "patches" a reader and a writer, consumes the reader stream and writes its contents to a Writer.
This is one of my favorite things about go - implicit interfaces. You don't have to declare you're implementing an interface, you just have to implement it to be used in some context. This allows mixing and matching of code that doesn't need to know about other code it's interacting with.
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func main() {
url := "http://i.imgur.com/m1UIjW1.jpg"
// don't worry about errors
response, e := http.Get(url)
if e != nil {
log.Fatal(e)
}
defer response.Body.Close()
//open a file for writing
file, err := os.Create("/tmp/asdf.jpg")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Use io.Copy to just dump the response body to the file. This supports huge files
_, err = io.Copy(file, response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println("Success!")
}
package main
import (
"io"
"net/http"
"os"
"fmt"
)
func main() {
img, _ := os.Create("image.jpg")
defer img.Close()
resp, _ := http.Get("http://i.imgur.com/Dz2r9lk.jpg")
defer resp.Body.Close()
b, _ := io.Copy(img, resp.Body)
fmt.Println("File size: ", b)
}
Try this:
package main
import (
"fmt"
"net/http"
"net/url"
"os"
"strings"
)
var (
fileName string
fullUrlFile string
)
func main() {
fullUrlFile = "https://i.imgur.com/m1UIjW1.jpg"
r, e := http.Get(fullUrlFile)
if e != nil {
panic(e)
}
defer r.Body.Close()
buildFileName()
// Create distination
f, e := os.Create(fileName) // "m1UIjW1.jpg"
if e != nil {
panic(e)
}
defer f.Close()
// Fill distination with content
n, e := f.ReadFrom(r.Body)
if e != nil {
panic(e)
}
fmt.Println("File size: ", n)
}
func buildFileName() {
fileUrl, e := url.Parse(fullUrlFile)
if e != nil {
panic(e)
}
path := fileUrl.Path
segments := strings.Split(path, "/")
fileName = segments[len(segments)-1]
println(fileName)
}
You can also use the ReadFrom method:
package main
import (
"net/http"
"os"
)
func main() {
r, e := http.Get("https://i.imgur.com/m1UIjW1.jpg")
if e != nil {
panic(e)
}
defer r.Body.Close()
f, e := os.Create("m1UIjW1.jpg")
if e != nil {
panic(e)
}
defer f.Close()
f.ReadFrom(r.Body)
}
https://golang.org/pkg/os#File.ReadFrom
What is the type of response.Body? You should just convert that into a []byte if it is not and write that to disk. There is no reason to use the image class unless you have some reason to treat the data as an image. Just treat the data as a series of bytes and write it to the disk.

Go - convert string which represent binary number into int

I wrote a stupid solution for this, any better recipe?
As you can see lots of useless conversions there.
package main
import (
"fmt"
"strconv"
"math"
)
func conv(str string) int {
l := len(str)
result := 0.0
for i,n := range str {
number,_ := strconv.Atof64(string(n))
result += math.Exp2(float64(l-i-1))*number
}
return int(result)
}
func main() {
fmt.Println(conv("1001"))
}
You want the strconv.ParseInt function, which converts from an arbitrary base, into a given bit size.
package main
import (
"fmt"
"strconv"
)
func main() {
if i, err := strconv.ParseInt("1001", 2, 64); err != nil {
fmt.Println(err)
} else {
fmt.Println(i)
}
}
Playground
For example, on Go 1,
package main
import (
"fmt"
"strconv"
)
func main() {
i, err := strconv.ParseInt("1101", 2, 64)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(i)
}
Output:
13

Resources