Go compiler undefined method - go

I am getting a compiler error "w.Write undefined (type rest.ResponseWriter has no field or method Write)"
I created a bare bones test file and have the same problem:
package server
import (
"github.com/ant0ine/go-json-rest/rest"
)
func WriteTest(w rest.ResponseWriter) {
var bs []byte
w.Write(bs)
}
The method that the compiler says is not defined is definitely in the rest package.

The rest.ReponseWriter type has no Write, it has the following methods:
Header
WriteJson
EncodeJson
WriteHeader
However, it says in the comments that http.ResponseWriter methods are available by type assertion. So you should be able to write the following:
package server
import (
"github.com/ant0ine/go-json-rest/rest"
"net/http"
)
func WriteTest(w rest.ResponseWriter) {
var bs []byte
w.(http.ResponseWriter).Write(bs)
}

Write is defined on responseWriter. Note the lowercase r.

Related

How to call unexported function within package?

I'm trying to write a package to work with. Here is sample code:
package redis
import (
"fmt"
"github.com/gomodule/redigo/redis"
"log"
"os"
)
var conn redis.Conn
func init() {
// code to set conn variable
}
func do(command string, args ...interface{}) (interface{}, error) {
init()
return conn.Do(command, args)
}
This code does not compile and compilator says undefined: init. When I change init() to Init() it works, but I don't want it to be available outside of package.
Wherever I read about this problem, it says about calling unexported function from another package, but here I'm calling it from same one.
Also, Goland IDE marks function call as unresolved reference and suggests to create it. But when I do (by IDE itself), it still doesn't see it.
init() is a special function. From the language spec:
func init() { … }
Multiple such functions may be defined per package, even within a
single source file. In the package block, the init identifier can
be used only to declare init functions, yet the identifier itself
is not declared. Thus init functions cannot be referred to from
anywhere in a program.
Use init() for package level initializations.
In Go, init is reserved for initializing work that needs to be done in a package, eg. adding some implementation to some registry.
To solve this problem, you need to use another name.
Take a look at this question to learn more about init if you are interested.

How to correctly import method from another package

I have the following simple project:
myapp/
|- mainlib/main.go
|- tables/sometable.go
In sometable.go I have:
package tables
import (
"fmt"
)
type TableName string
func (table TableName) GetDataFromDataSource() string {
return "getdatafromdatasource"
}
Those are methods, and now I want to use them in main.go:
package main
import t myapp/tables
type tableName t.TableName // and such "attempts"
I've tried:
t.GetDataFromDataSource()
t.tableName("string").GetDataFromDataSource()
tableName("string").GetDataFromDataSource()
and similar combinations and compiler says "undefined reference" still...
So, my question is: how to correctly use method from another package in such context? Of course my methods starts with captial letters and are exported. If I try to use simple function with same name (not method), then it works correctly...
This has nothing to do with packages, but with alias declaration vs type definition.
Let's take a simple example:
type A string
func (a A) Print() {
fmt.Println(a)
}
type B A
type C = A
func main() {
A("A").Print()
B("B").Print()
C("C").Print()
}
This fails to compile on line B("B").Print() with:
B("B").Print undefined (type B has no field or method Print)
The spec clearly spells out the difference in the type declarations section
The line type B A is a type definition:
A type definition creates a new, distinct type with the same
underlying type and operations as the given type, and binds an
identifier to it.
While the line type C = A is an alias declaration:
An alias declaration binds an identifier to the given type.
The former is a new type, so the receiver type A for method Print() will not match the type B.
The latter is just a name pointing to type A.
You'll want to change your code to the following, using type aliases:
import t myapp/tables
type tableName = t.TableName
tableName("string").GetDataFromDataSource()
And a few notes:
t.GetDataFromDataSource() can't work, it's a method and needs a receiver
t.tableName("string").GetDataFromDataSource() won't work, t.tableName is not a thing, or if it is, it's not exported
you can't talk about importing methods, only packages are imported. A method is either exported or not, but it's the package you import

Does a function have to satisfy the exact signature of a function type?

Consider the following simple go program
package main
import (
"io"
"encoding/json"
"os"
)
type MyEncoder interface {
Encode(v interface{}) error
}
type MyEncoderCreator func(io.Writer) *MyEncoder
type MyContainer struct {
Creator MyEncoderCreator
}
func main() {
container := Container{
Creator:json.NewEncoder,
}
encoder := container.Creator(os.Stdout)
encoder.Encode(map[string]string{"key":"value"})
}
This program fails to compile with the following error:
./main.go:21: cannot use json.NewEncoder (type func(io.Writer) *json.Encoder) as type MyEncoderCreator in field value
Why is this? The json.Encoder struct has a receiver that satisfies the MyEncoder interface. So should the json.NewEncoder function be allowed to assigned to MyContainer.Creator?
Yes, a function has to satisfy the exact signature of the function type. Similar things come up in other contexts: a more formal way to say it is that generally types in Go lack covariance. Here, you could wrap json.NewEncoder in a function returning MyEncoder.
I'd use the value type MyEncoder not the pointer *MyEncoder because if you store a pointer inside the interface value then generally you don't also need a pointer to the interface value just to avoid copies; here's more on pointers vs. values if it helps.

go generate: stringer: invalid operation: has no field or method String

I'm trying to use the stringer cmd so that I can generate String() methods for some int types. Here is how the code looks like
//go:generate stringer -type=MyIntType
type MyIntType int
const (
resource MyIntType = iota
)
func myfunc(){
print(resource.String())
}
The error I'm getting on go generate command is invalid operation: resource (constant 0 of type MyIntType) has no field or method String which makes sense because there is no String method yet. How am I supposed to fix this error if stringer cmd is supposed to actually generate the String method? Should I use fmt.Sprintf("%s", resource) all over the code ? it looks a bit ugly to me. At least not as nice as resource.String().
Each file must be parsed and type checked by the types library before the methods are generated. This usually doesn't pose a problem, since the String() method is rarely called directly, and is used by passing a value to something like fmt.Println that always checks first for a Stringer.
You can either not call String() yourself:
file: type.go
//go:generate stringer -type=MyIntType
package painkiller
import "fmt"
type MyIntType int
const (
resource MyIntType = iota
)
func myfunc() {
fmt.Println(resource)
}
Or you can put the calls in another file, and pass only the files that stringer needs as arguments. With no arguments, stringer checks the package as a whole, but if you provide only a list of files, they assume that some methods may be defined in files not provided.
file: type.go
//go:generate stringer -type=MyIntType type.go
package foo
type MyIntType int
const (
resource MyIntType = iota
)
file myfunc.go
package foo
func myfunc() {
print(resource.String())
}
The stringer cmd calls the go/parser.ParseFile for every go file. Thus if you have a method that is not declared it will fail. You will have to use fmt.Sprint* statements to get over this. Or you could tell go generate to only generate a specific file.
I don't know if we could term this as a bug. You could file it, probably see what the response is.

Package selection in Go

I'm trying to write an application to pull status from a database, but I seem to be getting stuck on a really basic principle of the language. I have the program written, but it doesn't compile due to the error use of package time not in selector.
A really basic example (from play.golang.org's own test environment)
package main
import (
"fmt"
"time"
)
func main() {
s_str := time.Now()
fmt.Println( printT(s_str) )
}
func printT(t time) time {
return t.Add(100)
}
Unfortunately, I've found documentation and helpdocs online a bit wanting. My understanding is that the import statement should include the library for the entire program like in C++ correct?
You have to prefix the imported types or variables with the name you gave to the package in the import (here you use the default name, that is "time"). That's what you did for the function Now but you have to do it also for the types.
So the type isn't time but time.Time (that is : the type Time that is declared in the package you import with the name "time").
Change your function to
func printT(t time.Time) time.Time {
return t.Add(100)
}
And for your second question : No, the import statement doesn't include the library for the entire program but only for the current file.

Resources