在赋值语句中使用字面量来表示类型。

huangapple go评论82阅读模式
英文:

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 的短变量声明。

Go 编程语言规范

短变量声明

短变量声明的语法如下:

ShortVarDecl = IdentifierList ":=" ExpressionList .

它是对带有初始化表达式但没有类型的常规变量声明的简写形式:

"var" IdentifierList = ExpressionList .

与常规变量声明不同,短变量声明可以重新声明变量,前提是它们在同一块中以相同的类型进行了原始声明,并且至少有一个非空白变量是新的。因此,重新声明只能出现在多变量的短声明中。重新声明不会引入新变量;它只是将新值分配给原始变量。

由于变量 u 已经在同一块中声明了(u *User),编译器会报错,提示“:= 左边没有新的变量”。对于简单的赋值,应该写成 u = User{}

语句 books := []Book{} 是在块中对新变量 books 进行短变量声明。

声明 u *User 表示 u 是指向类型为 User 的变量的指针。

Go 编程语言规范

复合字面量

复合字面量用于构造结构体、数组、切片和映射的值,并在每次求值时创建一个新值。它们由值的类型后跟大括号括起来的复合元素列表组成。元素可以是单个表达式或键值对。

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 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.

huangapple
  • 本文由 发表于 2014年8月16日 03:13:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/25332725.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定