This code works fine:
feedService := postgres.FeedService{}
feeds, err := feedService.GetAllRssFeeds()
But this code gives me error:
feeds, err = postgres.FeedService{}.GetAllRssFeeds()
controllers\feed_controller.go:35: cannot call pointer method on
postgres.FeedService literal controllers\feed_controller.go:35: cannot
take the address of postgres.FeedService literal
Why this two pieces of code is not equal ?
Here is a struct declaration:
type FeedService struct {
}
func (s *FeedService) GetAllRssFeeds() ([]*quzx.RssFeed, error) {
Your FeedService.GetAllRssFeeds() method has pointer receiver, so a pointer to FeedService is needed to call this method.
In your first example you use a short variable declaration to store a FeedService struct value in a local variable. Local variables are addressable, so when you write feedService.GetAllRssFeeds() after that, the compiler will automatically take the address of feedService and use that as the receiver value. It is a shorthand for:
feeds, err := (&feedService).GetAllRssFeeds()
It is in Spec: Calls:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m().
In your second example you don't create a local variable, you just use a struct composite literal, but by itself it is not (automatically) addressable, so the compiler cannot obtain a pointer to FeedService value to be used as the receiver, and hence cannot call the method.
Note that it is allowed to take the address of a composite literal explicitly, so the following also works:
feeds, err := (&postgres.FeedService{}).GetAllRssFeeds()
This is in Spec: Composite literals:
Taking the address of a composite literal generates a pointer to a unique variable initialized with the literal's value.
See related questions:
What is the method set of `sync.WaitGroup`?
Calling a method with a pointer receiver by an object instead of a pointer to it?
Related
I just started learning Go a few days ago.Today, we were debugging a piece of code for a while when we found something that seem counterintuitive of Go to do.
First we defined an interface and a data structure that implements it.
type Executer interface {
Execute()
}
type whatever struct {
name string
}
func (this *whatever) Execute() {
log.Println(this.name)
}
Now consider that I have a nil pointer to whatever and I try to call the method Execute. In other object-oriented languages I have used so far, this would call a null pointer error at the point of calling the method (i.e. w.Execute()) since the object pointer is null. Interestingly, in Go, the method is invoked, the null pointer error occurs at the Execute method when I try to dereference this.name. Why not at the point of calling the method?
func main() {
var w *whatever
w.Execute()
}
So, what I'm seeking to understand now is how is this possible? Does this mean that Go only does early method binding at compile time and at runtime there is no binding of the method with a specific object?
The receiver is just an "ordinary" argument to the function. Ordinary parameters may be of pointer types. When then are, you are allowed to pass nil as the argument, which is perfectly valid. All you need to keep in mind is not to dereference nil pointer arguments. The same applies to the special receiver parameter too. If it's a pointer, it may be nil, you just must not dereference it.
Spec: Method declarations:
The receiver is specified via an extra parameter section preceding the method name.
... The method is said to be bound to its receiver base type and the method name is visible only within selectors for type T or *T.
Allowing nil receiver values is not just something not forbidden, it has practical uses. For an example, see Test for nil values in nested stucts.
In Java you can call static methods on null objects too. It's true you can't do the same in Go, because Go does not have modifiers like static, public, private etc. In Go there are only exported and non-exported methods (implied by the first latter of their name).
But Go offers something similar too: Method expressions and Method values. If you have a method m with T receiver type, the expression T.m will be a function value whose signature contains the parameters and result types of m "prefixed" with the receiver type.
For example:
type Foo int
func (f Foo) Bar(s string) string { return fmt.Sprint(s, f) }
func main() {
fooBar := Foo.Bar // A function of type: func(Foo, string) string
res := fooBar(1, "Go")
fmt.Println(res)
}
Foo.Bar will be a function with type func (Foo, string) string, and you can call it like any other ordinary function; and you also have to pass the receiver as the first argument. The above app outputs (try it on the Go Playground):
Go1
Going a little "forward", we are not required to store Foo.Bar in a variable, we can directly call Foo.Bar:
fmt.Println(Foo.Bar(1, "Go"))
Which outputs the same (try it on the Go Playground). Now this almost looks like a static method call in Java.
And as the "final" step, when we use the above expression on a value of Foo itself (instead of the type identifier), we arrive at the method values, which saves the receiver and so the type of a method value does not include the receiver, its signature will be that of the method, and we can call it without having to pass a receiver:
var f Foo = Foo(1)
bar := f.Bar
fmt.Println(bar("Go"))
This again will output the same, try it on the Go Playground.
See related questions:
Pass method argument to function
golang function alias on method receiver
The official Go site writes as follows:
As the Go specification says, the method set of a type T consists of
all methods with receiver type T, while that of the corresponding
pointer type *T consists of all methods with receiver *T or T. That
means the method set of *T includes that of T, but not the reverse.
This distinction arises because if an interface value contains a
pointer *T, a method call can obtain a value by dereferencing the
pointer, but if an interface value contains a value T, there is no
safe way for a method call to obtain a pointer. (Doing so would allow
a method to modify the contents of the value inside the interface,
which is not permitted by the language specification.)
Even in cases where the compiler could take the address of a value to
pass to the method, if the method modifies the value the changes will
be lost in the caller.
My question is, when can't the compiler take a value to a pointer receiver value?
Addressable is defined in the https://golang.org/ref/spec#Address_operators:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
A counter examples include map values and functions:
func f() {}
func main() {
var m map[string]string
p1 := &m["foo"] // cannot take the address of m["foo"]
p2 := &f // cannot take the address of f
}
I am learning Go and found this code:
// newTestBlockChain creates a blockchain without validation.
func newTestBlockChain(fake bool) *BlockChain {
db, _ := ethdb.NewMemDatabase()
gspec := &Genesis{
Config: params.TestChainConfig,
Difficulty: big.NewInt(1),
}
gspec.MustCommit(db)
engine := ethash.NewFullFaker()
if !fake {
engine = ethash.NewTester()
}
blockchain, err := NewBlockChain(db, gspec.Config, engine, vm.Config{})
if err != nil {
panic(err)
}
blockchain.SetValidator(bproc{})
return blockchain
}
My question is:
gspec variable is created as an associative array of 2 values with key 'Config' and key 'Difficulty', that's clear.
But then I see this line:
gspec.MustCommit(db)
and I don't understand, where was the 'MustCommit()' function declared? Also, does an array in Go have methods? Weird stuff. Only class can have methods in my understanding of software development and here, I am seeing an array that has functions (methods). What is up with this code?
gspec variable is created as an associative array of 2 values with key
'Config' and key 'Difficulty' , that's clear.
It is not clear. It is false. Genesis is a struct. gspec is a pointer to a struct. A struct is not an associative array. In Go, a map is an associative array.
You have:
gspec := &Genesis{
Config: params.TestChainConfig,
Difficulty: big.NewInt(1),
}
Where
// Genesis specifies the header fields, state of a genesis block. It also defines hard
// fork switch-over blocks through the chain configuration.
type Genesis struct {
Config *params.ChainConfig `json:"config"`
Nonce uint64 `json:"nonce"`
Timestamp uint64 `json:"timestamp"`
ExtraData []byte `json:"extraData"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Mixhash common.Hash `json:"mixHash"`
Coinbase common.Address `json:"coinbase"`
Alloc GenesisAlloc `json:"alloc" gencodec:"required"`
// These fields are used for consensus tests. Please don't use them
// in actual genesis blocks.
Number uint64 `json:"number"`
GasUsed uint64 `json:"gasUsed"`
ParentHash common.Hash `json:"parentHash"`
}
https://godoc.org/github.com/ethereum/go-ethereum/core#Genesis
Composite literals
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
Taking the address of a composite literal generates a pointer to a
unique variable initialized with the literal's value.
gspec := &Genesis{
Config: params.TestChainConfig,
Difficulty: big.NewInt(1),
}
gspec is constructed using a Go composite literal.
Method declarations
A method is a function with a receiver. A method declaration binds an
identifier, the method name, to a method, and associates the method
with the receiver's base type.
The receiver is specified via an extra parameter section preceding the
method name. That parameter section must declare a single non-variadic
parameter, the receiver. Its type must be of the form T or *T
(possibly using parentheses) where T is a type name. The type denoted
by T is called the receiver base type; it must not be a pointer or
interface type and it must be defined in the same package as the
method.
A type of the form T or *T (possibly using parentheses), where T is a type name. may have methods; it must not be a pointer or interface type. A Go array type may have methods. A Go map (associative array) type may have methods. A Go struct type may have methods.
Go does not have classes.
References:
The Go Programming Language Specification
Your assumption is wrong. gspec isn't an associative array, but a object of type Genesis. The Genesis type is probably some sort of struct-type with various attributes and methods.
For examples on structs and methods you could visit the following Go by Example pages:
Structs
Methods
While calling json.Decoder.Decode by passing a struct, for instance
type _Sample struct {
first string // this will not be filled because it starts with lower case letter
Second string // it is OK.
}
...
var sample _Sample
err := decoder.Decode(&sample)
According to the Language Specification that writes:
Exported identifiers ΒΆ
An identifier may be exported to permit access to it from another package. An identifier is exported if both:
the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
the identifier is declared in the package block or it is a field name or method name.
All other identifiers are not exported.
The question is the struct _Sample is not exported, why it is visible by the package json?
Access permission is checked when
You're creating/declaring a variable. The compiler will check the visibility of the name of the type identifier.
Using reflect package to modify a variable.
Calling a constant, global variable, or a function. The visibility of constant/variable/function name will be checked.
Once the variable is created/defined, and when you pass this variable as a function/method argument, the copy (If it is a value, the value is being copied. If it is a pointer, the address is being copied) will be passed to the function/method, and always accessible from the function body through the argument name and type. In encoding/json package, the Decoder.Decode method is defined as,
func (dec *Decoder) Decode(v interface{}) error
thus, anything you passed to the Decoder.Decode method, is always accessible from inside the method body through argument v. Note that the type of v is interface{} not _Sample struct. The visibility is checked when you defined the variable as
var sample _Sample
which was OK since it is done from within the same package. Even an anonymous struct (i.e. no type name identifier is defined for the struct)
aSample := struct {
first string // this will not be filled because it starts with lower case letter
Second string // it is OK.
}{}
//...
err := decoder.Decode(&aSample)
will works. Next, when the decoder fills the struct (through reflection), the visibility of struct members will be checked, and _Sample.first is not visible from inside the json package.
Why don't I have to define PrintValue() as a pointer receiver (*One) to be able to print "hello"?
package main
import "fmt"
type One struct{
a string
}
func (o *One)AssignValue(){
o.a = "hello"
}
func (o One)PrintValue(){
fmt.Println(o.a)
}
func main() {
one := One{}
one.AssignValue()
one.PrintValue()
}
Because one is already of type One. The instantiation syntax
t := One{}
creates a value of type One while the form
p := &One{}
creates a pointer to a value of type One.
This means that nothing is to be done when calling t.PrintValue as the receiver type (One) is already the same as the type of t (One as well).
When calling p.PrintValue the compiler automatically converts an addressable variable to its pointer form because the receiver type (One) is not equal to the type of p (*One). So the expression
p.PrintValue()
is converted to
(*p).PrintValue()
There is also a conversion necessary when calling t.AssignValue as this method has a pointer receiver but we're supplying a value. This is also done automatically by the compiler where possible.
From the spec on calls:
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
This means the expression
t.AssignValue()
is converted to
(&t).AssignValue()
Note that this is not always possible. For example when returning a value from a function:
func NewOne(s string) One { return One{s} }
NewOne("foo").AssignValue() // Not possible
x := NewOne("foo")
x.AssignValue() // Possible, automatically converted