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)
}
}
好的,所以这可能会被关闭,因为这是一个简单的打字错误,或者只是RT(f(M的一个例子。我建议你走一趟高尔夫之旅。导出的名称在基础的第3页中进行了解释,所以基本上是在教程开始时。如果你根本没有看过巡演,巡演从这里开始
尽管如此,我还是会用你的特定代码回答你的问题:
在戈兰,资本化很重要。在您的案例中,您有一个名为entities
的包,在其中您定义了类型Task
,其大写字母为T。因为您使用大写字母作为名称的第一个字符,所以类型为导出。当您在taskcontroller
软件包中import
和entities
软件包时,您将能够使用entities.Task
。你写过吗:
package entities
type task struct {}
您将不能写入t := entities.task{}
。用传统OOP术语来说:任何以小写字符开头的名称都是私有的。如果它们以大写字母开头,那么它们就是公共的。
现在看看你的类型:
type Task struct {
Id int64
task string
assignee string
deadline string
action string
}
您有一个名为Task
的公共类型,包含5个字段。一个字段(Id
(是公共的,可以在entities
包之外访问。其他四个字段是private,只能从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",
}
// or
task.Assignee = "bar"
}
不过,有时您可能希望限制/控制对类似字段的访问,在这种情况下,您可以使用getters/ssetter。同样,同样的规则适用于WRT资本化:
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{}
}
通过这些方法,您可以在其他包中使用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: %vn", err)
return
}
fmt.Printf("Task assigned to %sn", 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()
}
正如您所看到的,虽然我不能在main
包之外直接调用reset
,但我可以调用内部调用reset
的导出方法。