任务.Task未定义(类型entities.Task没有字段或方法Task)

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

task.Task undefined (type entities.Task has no field or method Task)

问题

package entities

type Task struct {
	Id       int64
	task     string
	assignee string
	deadline string
	action   string
}
package taskcontroller

import (
	"fmt"
	"html/template"
	"net/http"

	"github.com/jeypc/go-crud/config/entities"
)

func Index(response http.ResponseWriter, request *http.Request) {
	temp, err := template.ParseFiles("config/views/task/index.html")

	if err != nil {
		panic(err)
	}
	temp.Execute(response, nil)
}

func Add(response http.ResponseWriter, request *http.Request) {

	if request.Method == http.MethodGet {

		temp, err := template.ParseFiles("config/views/task/add.html")

		if err != nil {
			panic(err)
		}
		temp.Execute(response, nil)

	} else if request.Method == http.MethodPost {

		request.ParseForm()

		var task entities.Task

		task.Task = request.Form.Get("task")
		task.Assignee = request.Form.Get("assignee")
		task.Deadline = request.Form.Get("deadline")

		fmt.Println(task)

	}

}
英文:
package entities

type Task struct {
	Id       int64
	task     string
	assignee string
	deadline string
	action   string
}
package taskcontroller

import (
	"fmt"
	"html/template"
	"net/http"

	"github.com/jeypc/go-crud/config/entities"
)

func Index(response http.ResponseWriter, request *http.Request) {
	temp, err := template.ParseFiles("config/views/task/index.html")

	if err != nil {
		panic(err)
	}
	temp.Execute(response, nil)
}

func Add(response http.ResponseWriter, request *http.Request) {

	if request.Method == http.MethodGet {

		temp, err := template.ParseFiles("config/views/task/add.html")

		if err != nil {
			panic(err)
		}
		temp.Execute(response, nil)

	} else if request.Method == http.MethodPost {

		request.ParseForm()

		var task entities.Task

		task.Task = request.Form.Get("task")
		task.Assignee = request.Form.Get("assignee")
		task.Deadline = request.Form.Get("deadline")

		fmt.Println(task)

	}

}

答案1

得分: 1

好的,以下是翻译好的内容:

好的,这个问题可能会被关闭,因为这只是一个简单的拼写错误,或者只是一个RT(f)M的情况。我建议你按照Go语言的教程进行学习。关于导出的名称的解释在基础知识的第3页上,所以基本上在教程的开头部分。如果你还没有看过教程,教程从这里开始

不过,我会使用你提供的代码来回答你的问题:

在Go语言中,大小写是有区别的。在你的代码中,你有一个名为entities的包,在其中定义了一个名为Task的类型,T是大写的。因为你使用大写作为名称的第一个字符,这个类型是_导出的_。当你在taskcontroller包中importentities包后,你就可以使用entities.Task。如果你写成了:

package entities
type task struct {}

你将不能写成t := entities.task{}。换句话说,按照传统的面向对象编程的术语来说:以小写字母开头的名称是私有的,以大写字母开头的名称是公共的。

现在来看看你的类型:

type Task struct {
Id       int64
task     string
assignee string
deadline string
action   string
}

你有一个名为Task的公共类型,有5个字段。其中一个字段(Id)是公共的,可以在entities包之外访问。其他四个字段是_私有的_,只能在entities包内部访问。

现在,你想在taskcontroller包中设置assigneetask等字段。但是你不能这样做,因为它们是_私有的_。要能够访问这些字段,最简单的方法是修改entities.Task类型,将字段设为公共的:

type Task struct {
Id       int64
Task     string
Assignee string
Deadline string
Action   string
}

然后,你就可以在其他包中访问所有字段了:

package taskcontroller
import "entities"
func someFunc() {
task := entities.Task{
Id:   123,
Task: "foo",
}
// 或者
task.Assignee = "bar"
}

然而,有时你可能希望限制/控制对这些字段的访问,这时你可以使用getter和setter方法。同样,大小写规则也适用于这里:

package entities
// Task与你现在的代码一样,有未导出的字段
type Task struct {
Id       int64
task     string
assignee string
deadline string
action   string
}
// SetAssignee以大写字母S开头,所以可以从其他包中调用
// 这个方法可以用于验证/规范化/...
// 你需要为每个字段添加SetX方法
func (t *Task) SetAssignee(assignee string) error {
if len(assignee) > 255 {
return errors.New("assignee too long, max length is 255")
}
// assignee没有被导出,但是使用这个方法可以设置它的值
t.assignee = assignee
return nil
}
// GetAssignee被导出,可以在任何地方调用
// 同样,你需要为每个未导出的字段实现一个GetX方法
// 可以用于返回默认值,例如
func (t Task) GetAssignee() string {
if len(t.assignee) == 0 {
return "none"
}
return t.assignee
}
func (t *Task) ToMapAndClear() map[string]interface{} {
// 创建一个包含数据的映射
r := map[string]interface{}{
"id":       t.Id,
"task":     t.task,
"assignee": t.assignee,
"deadline": t.deadline,
"action":   t.action,
}
// 清空所有字段。我们可以从包内部调用reset方法
t.reset()
return r
}
// ExtractMap与上面的函数相同,但使用了defer,所以更简洁
func (t *Task) ExtractMap() map[string]interface{} {
defer t.reset()
return map[string]interface{}{
"id":       t.Id,
"task":     t.task,
"assignee": t.assignee,
"deadline": t.deadline,
"action":   t.action,
}
}
// reset以小写字母s开头,所以不能在包外部调用
func (t *Task) reset() {
*t = Task{}
}

有了这些方法,你可以在其他包中使用entities.Task类型,像这样:

package main
import (
"fmt"
"entities"
)
func main() {
t := entities.Task{
Id: 123,
}
if err := t.SetAssignee("Benjamin"); err != nil {
fmt.Printf("Could not set assignee: %v\n", err)
return
}
fmt.Printf("Task assigned to %s\n", t.GetAssignee()) // 正常工作
// 不能工作
t.reset() // main包无法访问reset方法
// 这个可以工作 - 我们将值放入映射中,并在内部调用reset
data := t.ExtractMap()
}

正如你所看到的,虽然我不能直接在main包之外调用reset,但我可以调用调用reset的导出方法。

英文:

OK, so this is probably going to get closed, as this is a simple typo, or just a case of RT(f)M. I'd recommend you walk through the golang tour. Exported names is something explained on page 3 of the basics, so pretty much at the start of the tour. If you haven't looked at the tour at all, the tour starts here

Still, I'll answer your question using your specific code:

In golang, capitalisation matters. In your case, you have a package called entities, in which you define the type Task, with a capital T. Because you're using a capital as the first character of the name, the type is exported. When you import the entities package in your taskcontroller package, you'll be able to use entities.Task. Had you written:

package entities
type task struct {}

you would not be able to write t := entities.task{}. To put it in conventional OOP terms: any name beginning with a lower-case character is private. If they start with an upper-case character, they are public.

Now looking at your type:

type Task struct {
Id       int64
task     string
assignee string
deadline string
action   string
}

You have a public type called Task, with 5 fields. One field (Id) is public, and can be accessed outside of the entities package. The other four fields are private, and can only be accessed from inside the entities package.

Now, you're trying to set fields like assignee, task, and so on in the taskcontroller package. You can't do that, because they are private. To be able to access these fields, the simplest way is to change the entities.Task type and make the fields public:

type Task struct {
Id       int64
Task     string
Assignee string
Deadline string
Action   string
}

Then, you'll be able to access all fields in other packages:

package taskcontroller
import "entities"
func someFunc() {
task := entities.Task{
Id:   123,
Task: "foo",
}
// or
task.Assignee = "bar"
}

Sometimes, though, you may want to limit/control access to fields like this, in which case you can use getters/setters. Again, the same rule applies WRT capitalisation:

package entities
// Task as you have it now, with unexported fields
type Task struct {
Id       int64
task     string
assignee string
deadline string
action   string
}
// SetAssignee starts with upper-case S, so can be called from other packages
// this method can be used for validation/normalisation/...
// you'll need to add SetX for each field
func (t *Task) SetAssignee(assignee string) error {
if len(assignee) > 255 {
return errors.New("assignee too long, max length is 255")
}
// assignee is not exported, but using this function its value can be set
t.assignee = assignee
return nil
}
// GetAssignee is exported, can be called everywhere
// again, you'll need to implement a GetX for each unexported field
// can be used to return default values, for example
func (t Task) GetAssignee() string {
if len(t.assignee) == 0 {
return "none"
}
return t.assignee
}
func (t *Task) ToMapAndClear() map[string]interface{} {
// create a map containing the data
r := map[string]interface{}{
"id":       t.Id,
"task":     t.task,
"assignee": t.assignee,
"deadline": t.deadline,
"action":   t.action,
}
// clear all fields. We can call reset from inside the package
t.reset()
return r
}
// ExtractMap same function as above, but with defer so it's less verbose
func (t *Task) ExtractMap() map[string]interface{} {
defer t.reset()
return map[string]interface{
"id":       t.Id,
"task":     t.task,
"assignee": t.assignee,
"deadline": t.deadline,
"action":   t.action,
}
}
// reset starts with lower-case s, so cannot be called outside of this package
func (t *Task) reset() {
*t = Task{}
}

With these methods, you can use the entities.Task type in other packages like so:

package main
import (
"fmt"
"entities"
)
func main() {
t := entities.Task{
Id: 123,
}
if err := t.SetAssignee("Benjamin"); err != nil {
fmt.Printf("Could not set assignee: %v\n", err)
return
}
fmt.Printf("Task assigned to %s\n", t.GetAssignee()) // works fine
// does not work
t.reset() // main package does not have access to reset method
// this does work - we get the values in a map, and reset gets called internally
data := t.ExtractMap()
}

As you can see, though I can't call reset directly outside of the main package, I can call exported methods that call reset internally.

huangapple
  • 本文由 发表于 2022年8月8日 15:21:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/73274149.html
匿名

发表评论

匿名网友

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

确定