英文:
use a literal for type in assignment
问题
我正在使用func Root
中的代码作为指南来创建另一个名为Login
的方法,如下所示。特别是在Root
中,我将字面量Book{}
赋给b
,然后在Scan
中使用结果。那段代码没有抛出任何错误(尽管我不确定它是否是好的代码),但是当我尝试在Login
函数中做类似的事情时,我得到了这个错误:
cannot use User literal (type User) as type *User in assignment
值得一提的是,当我编译时,在上面也会得到这个错误:
no new variables on left side of :=
但是在第二个方法中,我不是在做同样的事情吗?也就是将字面量u := User{}
赋给一个变量,然后在扫描中使用它?
您能否解释一下在赋值中何时可以使用类型字面量和何时不可以,使用下面的代码进行说明:
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)
}
...//省略的代码
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
}
英文:
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
}
答案1
得分: 10
简化你的示例以关注要点:
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) {
// 左边没有新的变量
// 不能将 User 字面量(类型为 User)赋值给类型为 *User 的变量
// u := User{}
u = &User{}
return
}
func main() {}
Login
函数声明了一个结果参数 u *User
,它是指向类型 User
的指针。
u := User{}
语句是对类型 User
的短变量声明。
短变量声明的语法如下:
ShortVarDecl = IdentifierList ":=" ExpressionList .
它是对带有初始化表达式但没有类型的常规变量声明的简写形式:
"var" IdentifierList = ExpressionList .
与常规变量声明不同,短变量声明可以重新声明变量,前提是它们在同一块中以相同的类型进行了原始声明,并且至少有一个非空白变量是新的。因此,重新声明只能出现在多变量的短声明中。重新声明不会引入新变量;它只是将新值分配给原始变量。
由于变量 u
已经在同一块中声明了(u *User
),编译器会报错,提示“:=
左边没有新的变量”。对于简单的赋值,应该写成 u = User{}
。
语句 books := []Book{}
是在块中对新变量 books
进行短变量声明。
声明 u *User
表示 u
是指向类型为 User
的变量的指针。
复合字面量用于构造结构体、数组、切片和映射的值,并在每次求值时创建一个新值。它们由值的类型后跟大括号括起来的复合元素列表组成。元素可以是单个表达式或键值对。
LiteralType 必须是结构体、数组、切片或映射类型(除非类型以 TypeName 给出,语法规定了这个约束)。表达式的类型必须可以赋值给 LiteralType 的相应字段、元素和键类型;不需要进行额外的转换。
对复合字面量取地址会生成指向字面量值的唯一实例的指针。
复合字面量 User{}
是类型为 User
而不是 *User
的字面量值。编译器会报错“cannot use User literal (type User) as type *User in assignment
”。要获取指向类型为 User
的字面量值的指针(*User
),应该写成 u = &User{}
。
英文:
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{}
.
答案2
得分: 2
-
b := Book{}
定义了一个新的变量 (b
之前没有定义),因此它可以取值类型Book
。 -
u := User{}
不定义一个新的变量,因为它是方法返回参数u *User
的一部分,所以不能使用:=
。应该使用u=&User{}
。
这里的u
是一个命名返回参数:
> 如果函数执行一个没有参数的返回语句,那么结果参数的当前值将作为返回值使用。
英文:
b := Book{}
defines a new variable (b
wasn't defined before), so it can take the value typeBook
u := User{}
doesn't define a new variable, because it was part of the method return parameteru *User
, so you can't use:=
.
It would beu=&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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论