Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use a literal for type in assignment

Tags:

go

I'm using the code in func Root as a guide to create another method Login shown below. In particular, in Root, I assign the literal Book{} to b and then use the result in the Scan. That code doesn't throw any errors (although I'm not sure if it's nice code), but when I try to do something similar in the Login function, which I'm modifying from this blogpost, I get this error

cannot use User literal (type User) as type *User in assignment

for what it's worth, I also get this error right above when I compile

no new variables on left side of :=

but aren't I doing the same thing in the second method, namely assigning the literal u := User{} to a variable and then using it in the scan?

Can you explain using the code below when you can and can't use a literal for type in an assignment?

func Root(w http.ResponseWriter, r *http.Request) {

    rows, err := db.Query("SELECT title, author, description FROM books")
    books := []Book{}
    for rows.Next() {
        b := Book{}
        err := rows.Scan(&b.Title, &b.Author, &b.Description)
        PanicIf(err)
        books = append(books, b)
    }
    ...//code ommitted



func Login(password, email string) (u *User, err error) {
    u := User{}
    db.QueryRow("select * from users where email=$1 ", email).Scan(&u.Id, &u.Password, &u.Email)
    if err != nil {
        return
    }

    err = bcrypt.CompareHashAndPassword(u.Password, []byte(password))
    if err != nil {
        u = nil
    }
    return
}
like image 700
Leahcim Avatar asked Aug 15 '14 19:08

Leahcim


2 Answers

Simplifying your example to focus on the essentials:

package main

import "net/http"

type Book struct{}

type User struct{}

func Root(w http.ResponseWriter, r *http.Request) {
    books := []Book{}
    _ = books
}

func Login(password, email string) (u *User, err error) {
    // no new variables on left side of :=
    // cannot use User literal (type User) as type *User in assignment
    // u := User{}
    u = &User{}
    return
}

func main() {}

The function declaration for Login declares a result parameter u *User, a pointer to type User.

The u := User{} statement is a short variable declaration of type User.

The Go Programming Language Specification

Short variable declarations

A short variable declaration uses the syntax:

ShortVarDecl = IdentifierList ":=" ExpressionList .

It is shorthand for a regular variable declaration with initializer expressions but no types:

"var" IdentifierList = ExpressionList .

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.

Since the variable u has already been declared in the same block (u *User), the compiler complains that u := User{} has "no new variables on left side of :=." Write u = User{} for a simple assignment.

The statement books := []Book{} is a short variable declaration for a new variable, book, in the block.

The declaration u *User says that u is a pointer to a variable of type User.

The Go Programming Language Specification

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 value followed by a brace-bound list of composite elements. An element may be a single expression or a key-value pair.

The LiteralType must be a struct, array, slice, or map type (the grammar enforces this constraint except when the type is given as a TypeName). The types of the expressions must be assignable to the respective field, element, and key types of the LiteralType; there is no additional conversion.

Taking the address of a composite literal generates a pointer to a unique instance of the literal's value.

The composite literal User{} is a literal value of type User, not *User. The compiler complains that "cannot use User literal (type User) as type *User in assignment." Take the address of the composite literal for a pointer to a literal value of type User (*User). Write u = &User{}.

like image 116
peterSO Avatar answered Oct 16 '22 13:10

peterSO


  • b := Book{} defines a new variable (b wasn't defined before), so it can take the value type Book
  • u := User{} doesn't define a new variable, because it was part of the method return parameter u *User, so you can't use :=.
    It would be u=&User{}.

u here is a named result parameter:

if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.

like image 36
VonC Avatar answered Oct 16 '22 14:10

VonC