Can structs be nil?

4,323 views
Skip to first unread message

m

unread,
Aug 3, 2010, 8:35:17 PM8/3/10
to golang-nuts
Seems not, this won't compile for some reason. I'm just testing to
see if a struct is nil or not.
s := GetSiteUser(username, password)

if s == nil {
return "Doesn't exist"
}



When I make, this happens:

cannot use nil as SiteUser

Clark Gaebel

unread,
Aug 3, 2010, 8:35:54 PM8/3/10
to golan...@googlegroups.com
Why not use a pointer to a structure?

--
Regards,
-Clark

m

unread,
Aug 3, 2010, 8:47:18 PM8/3/10
to golang-nuts
I honestly don't get pointers. Never used C. What am I pointing
out. The variable name or the type. Also, what is "&" mean.

Andrew Gerrand

unread,
Aug 3, 2010, 8:48:40 PM8/3/10
to m, golang-nuts

The zero-value of a struct type is the struct with all its elements
set to their zero values.

Eg,

type T struct {
a int
b string
c *byte
}

var t T
// t == T{0, "", nil}

A value that is not of pointer, channel, map, or slice type cannot be nil.

Andrew

Andrew Gerrand

unread,
Aug 3, 2010, 8:55:34 PM8/3/10
to m, golang-nuts
On 4 August 2010 10:47, m <phill...@gmail.com> wrote:
> I honestly don't get pointers.  Never used C.  What am I pointing
> out.  The variable name or the type.  Also, what is "&" mean.

A pointer a memory address of a piece of data. Here is a video that
explains it all:
http://www.youtube.com/watch?v=UvoHwFvAvQE

But in short:

var i int = 1
var p *int = &i

i is a variable of type int with value 1
p is a variable of type pointer-to-int with value [memory address of i]

& means "address of" - it returns the memory address of a value.
* has two meanings, either "pointer to" (in a type definition) or
"dereference" (in an expression).

Dereferencing means "return the value at". Continuing the example above:

var j int = *p

j is a variable of type int with the value at the memory address p. In
this case, 1.

nil is the zero-value of a pointer type. (it doesn't point to anything)

Andrew

m

unread,
Aug 3, 2010, 8:58:38 PM8/3/10
to golang-nuts
Thanks for the quick lesson. It will take me a while to get the
handle on it. What do I need to do for my code then? Does
GetSiteUser(username, password) need to return a *SiteUser?

On Aug 3, 8:55 pm, Andrew Gerrand <a...@golang.org> wrote:

m

unread,
Aug 3, 2010, 9:13:53 PM8/3/10
to golang-nuts
Turning it all into pointers gets me through a make. However when I
actually run the code things blow up spectacularly.

panic: runtime error: invalid memory address or nil pointer
dereference

On Aug 3, 8:55 pm, Andrew Gerrand <a...@golang.org> wrote:

✖ chris tighe ✖

unread,
Aug 3, 2010, 9:14:59 PM8/3/10
to m, golang-nuts
Can you please post the code? :)

-cbt

Clark Gaebel

unread,
Aug 3, 2010, 9:14:12 PM8/3/10
to golan...@googlegroups.com
Well, you see, you can't actually DEREFERENCE the nil pointer. It
points to, literally, nothing. The object at the other end will be
garbage collected and any attempts to dereference will (as you saw) blow up.

--
Regards,
-Clark

m

unread,
Aug 3, 2010, 9:19:34 PM8/3/10
to golang-nuts
GetSiteUserByUsername is the function where things go haywire.


package dbhelper

import (
mongo "github.com/mikejs/gomongo/mongo"
"io"
"fmt"
"crypto/sha256"
"rand"
"strconv"
)

type SiteUser struct {
ID int64;
Username string;
Passhash string;
Salt int64;
}

func LoginSiteUser(user string, password string) (SiteUser, bool) {
// Get the existing user from the database.
e := GetSiteUserByUsername(user)

// If the site user is empty, return.
if e.Username == "" {
n := &SiteUser{Username:""}
return *n, false
}

// Otherwise, check the password.
hash := createHashedPass(password, e.Salt)
fmt.Println("New hash: " + hash + "\nOld hash: " + e.Passhash)
if hash != e.Passhash {
n := new(SiteUser)
return *n, false
}

// If we've gotten this far, successful login.
return *e, true
}

func GetSiteUserByUsername(user string) *SiteUser {
conn, _ := mongo.Connect("127.0.0.1")
coll := conn.GetDB("mysite_dev").GetCollection("siteuser")

// Query the db.
qFindDoc, _ := mongo.Marshal(&SiteUser{Username:user})
bsonDocOut, _ := coll.FindOne(qFindDoc)
var foundUser *SiteUser
mongo.Unmarshal(bsonDocOut.Bytes(), &foundUser)

return foundUser
}

func CreateSiteUser(user string, password string) {
e := GetSiteUserByUsername(user)
if e.Username != "" { return }

salt := createSalt()
hash := createHashedPass(password, salt)

// Now create a new instance of the SiteUser struct.
s := new(SiteUser)
s.Username = user
s.Passhash = hash
s.Salt = salt

// And save the results to the database.
conn, _ := mongo.Connect("127.0.0.1")
coll := conn.GetDB("mysite_dev").GetCollection("siteuser")
bsonDocIn, _ := mongo.Marshal(s)
coll.Insert(bsonDocIn)
}

func createSalt() int64 {
// This function only creates a salt to user. Nothing more.
return rand.Int63()
}

func createHashedPass(password string, salt int64) string {
// Use sha256 to create the hashed password.
b := sha256.New()
io.WriteString(b, password + strconv.Itob64(salt, 10))
hash := fmt.Sprintf("%x", b.Sum())

return hash

Clark Gaebel

unread,
Aug 3, 2010, 9:20:36 PM8/3/10
to golan...@googlegroups.com

My guess is that...

func GetSiteUserByUsername(user string) *SiteUser {
conn, _ := mongo.Connect("127.0.0.1")
coll := conn.GetDB("mysite_dev").GetCollection("siteuser")

// Query the db.
qFindDoc, _ := mongo.Marshal(&SiteUser{Username:user})
bsonDocOut, _ := coll.FindOne(qFindDoc)
var foundUser *SiteUser
mongo.Unmarshal(bsonDocOut.Bytes(), &foundUser)

return foundUser
}


Needs to be...

func GetSiteUserByUsername(user string) *SiteUser {
conn, _ := mongo.Connect("127.0.0.1")
coll := conn.GetDB("mysite_dev").GetCollection("siteuser")

// Query the db.
qFindDoc, _ := mongo.Marshal(&SiteUser{Username:user})
bsonDocOut, _ := coll.FindOne(qFindDoc)

var foundUser SiteUser
mongo.Unmarshal(bsonDocOut.Bytes(), &foundUser)

return &foundUser
}

--
Regards,
-Clark

✖ chris tighe ✖

unread,
Aug 3, 2010, 9:32:03 PM8/3/10
to Clark Gaebel, golan...@googlegroups.com
On Tue, Aug 3, 2010 at 9:14 PM, Clark Gaebel <cg.wowus.cg@gmail.com> wrote:
 Well, you see, you can't actually DEREFERENCE the nil pointer. It
points to, literally, nothing. The object at the other end will be
garbage collected and any attempts to dereference will (as you saw) blow up.


are go pointers that aren't yet pointing to something called nil?  I was under the impression that a null pointer was pointing to nothing (because nil = 0; null = nothing). sorry for the silly question :).

cbt

Clark Gaebel

unread,
Aug 3, 2010, 9:34:22 PM8/3/10
to ✖ chris tighe ✖, golan...@googlegroups.com
nil == null == 0 (for pointers)

It's all terminology.

On 08/03/10 21:32, ✖ chris tighe ✖ wrote:

--
Regards,
-Clark

m

unread,
Aug 3, 2010, 9:40:17 PM8/3/10
to golang-nuts
Thanks everyone. Still getting same results after changing Clark's
code. I don't understand what dereferencing means.

Clark Gaebel

unread,
Aug 3, 2010, 9:41:08 PM8/3/10
to golan...@googlegroups.com
If you have a pointer to nil, and you try to call any method with it,
or do *pointer, you will dereference it. Since, by definition, it
doesn't point to anything, it will error out on you.

Oh how I miss the days of segfaults.

--
Regards,
-Clark

m

unread,
Aug 3, 2010, 9:46:31 PM8/3/10
to golang-nuts
What do you mean "call any method with it"? As an in parameter? Out
parameter? Either?

Clark Gaebel

unread,
Aug 3, 2010, 10:00:55 PM8/3/10
to golan...@googlegroups.com
As in like...

var someObject *Object // Initialized to nil
someObject.SomeMethod()

--
Regards,
-Clark

konrad

unread,
Aug 3, 2010, 11:28:03 PM8/3/10
to golang-nuts
Shouldn't the GetSiteUserByUsername Function be?

func GetSiteUserByUsername(user string) *SiteUser {
conn, _ := mongo.Connect("127.0.0.1")
coll := conn.GetDB("mysite_dev").GetCollection("siteuser")

// Query the db.
qFindDoc, _ := mongo.Marshal(&SiteUser{Username:user})
bsonDocOut, _ := coll.FindOne(qFindDoc)
foundUser := new(SiteUser)
mongo.Unmarshal(bsonDocOut.Bytes(), foundUser)

return foundUser

Kees

unread,
Aug 4, 2010, 12:11:14 AM8/4/10
to golang-nuts
I always feel that pointer syntax is the wrong way around. You define
a pointer type with *, but when you dereference, or "depointerize",
you use * as well. Would have made more sense to use the same symbols
for declarations and referencing, not declarations and dereferencing.
Or just use 3 different symbols altogether.

Kees

On Aug 4, 12:55 pm, Andrew Gerrand <a...@golang.org> wrote:

Jessta

unread,
Aug 4, 2010, 12:54:10 AM8/4/10
to Kees, golang-nuts
On Wed, Aug 4, 2010 at 2:11 PM, Kees <kees.v...@gmail.com> wrote:
> I always feel that pointer syntax is the wrong way around. You define
> a pointer type with *, but when you dereference, or "depointerize",
> you use * as well. Would have made more sense to use the same symbols
> for declarations and referencing, not declarations and dereferencing.
> Or just use 3 different symbols altogether.

In C it makes a lot of sense,
int *age; says, if you deference age you'll get a int

this is commonly miswritten as
int* age; with int* being referred to a type of 'pointer to int'

The Go syntax plays on this misunderstanding and changing it would be
be confusing to past C and C++ users without reason.
var age *int

- jessta


--
=====================
http://jessta.id.au

Andrew Gerrand

unread,
Aug 4, 2010, 1:29:40 AM8/4/10
to Jessta, Kees, golang-nuts

Rob wrote a good blog post on this topic:
http://blog.golang.org/2010/07/gos-declaration-syntax.html

Andrew

roger peppe

unread,
Aug 4, 2010, 5:09:33 AM8/4/10
to Clark Gaebel, golan...@googlegroups.com
On 4 August 2010 02:41, Clark Gaebel <cg.wo...@gmail.com> wrote:
>  If you have a pointer to nil, and you try to call any method with it,
> [...], you will dereference it. Since, by definition, it

> doesn't point to anything, it will error out on you.

actually that's a common misunderstanding.
calling a method on a nil pointer does not necessarily
dereference the pointer. because the pointer has a known
type, the runtime knows which method to call without
looking inside the pointer. the method will get be called with a
receiver value.

one exception is when a value method is called on
a pointer value, in which case the runtime needs to
dereference the value in order to pass it to the method.

interfaces are not pointers, even though they can
be nil - calling a method on a nil interface
*will* panic.

Russ Cox

unread,
Aug 4, 2010, 1:51:06 PM8/4/10
to m, golang-nuts
On Tue, Aug 3, 2010 at 17:47, m <phill...@gmail.com> wrote:
> I honestly don't get pointers.  Never used C.  What am I pointing
> out.  The variable name or the type.  Also, what is "&" mean.

http://www.cs.stanford.edu/cslibrary/PointerFunCBig.avi

(If you can ignore the fact that clay is talking to you,
it does do a good job of explaining what pointers are.)

Russ

Reply all
Reply to author
Forward
0 new messages