英文:
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
包中import
了entities
包后,你就可以使用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
包中设置assignee
、task
等字段。但是你不能这样做,因为它们是_私有的_。要能够访问这些字段,最简单的方法是修改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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论