Перейти шаблон не может вызвать метод на поле - PullRequest
0 голосов
/ 16 октября 2019

У меня есть оболочка вокруг net/mail.Address, которая обеспечивает некоторую логику сортировки. Я пытаюсь использовать его в шаблоне, но получаю can't evaluate field String in type EmailAddress. Документы шаблона говорят:

Имя метода niladic данных, которому предшествует точка, например

.Method

Результатом является значениевызова метода с точкой в ​​качестве получателя, dot.Method ().

и

Вызовы метода могут быть объединены в цепочку и объединены с полями и ключами любой глубины:

.Field1.Key1.Method1.Field2.Key2.Method2

Итак, имея в виду, я написал это:

package main

import (
    "bytes"
    "fmt"
    "html/template"
    "net/mail"
    "os"
)

type EmailAddress struct{ mail.Address }

type emailFormatter struct {
    From         EmailAddress
    To           EmailAddress
}

var tmpl = template.Must(template.New("Sample Text").Parse("From: {{.From.String}}\r" + `
To: {{.To.String}}` + "\r" + `
Content-Type: text/html` + "\r" + `
Subject: Sample Text` + "\r\n\r" + `
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Sample Text</title>
    <meta charset="utf-8"/>
</head>
<body>
    Sample Text
</body>
</html>
`));

func main() {
    to := EmailAddress{
        mail.Address{
            Address: "em@i.l",
            Name: "",
        },
    }
    from := EmailAddress{
        mail.Address{
            Address: "no-reply@test.quest",
            Name: "",
        },
    }

    fmt.Println(to.String()) //outputs (as expected) "<em@i.l>"
    fmt.Println(from.String()) //outputs (as expected) "<no-reply@test.quest>"

    f := emailFormatter{
        To: to,
        From: from,
    }

    var buff bytes.Buffer
    if err := tmpl.Execute(&buff, f); err != nil {
        fmt.Printf("Error: %v\n", err)
        os.Exit(1)
    }
    fmt.Println(buff.String())
}

Имеюотдельно проверил, что вызов EmailAddress.String является полностью законным, поэтому я не могу понять, почему единственный вывод этого:

Error: template: Sample Text:1:13: executing "Sample Text" at <.From.String>: can't evaluate field String in type main.EmailAddress

РЕДАКТИРОВАТЬ

По предложению комментатора я изменил вызовыот .From.String и .To.String до .From.Address.String и .To.Address.String, потому что

"String не определено в EmailAddress, определено в EmailAddress.Address"

но результат тот же:

Error: template: Sample Text:1:13: executing "Sample Text" at <.From.Address.String>: can't evaluate field String in type mail.Address

1 Ответ

2 голосов
/ 16 октября 2019

Поскольку String определяется с помощью приемника указателя, вам нужно передать «адресуемый» экземпляр mail.Address в шаблон, чтобы иметь возможность выполнить этот метод.

Выэто можно сделать, передав указатель на f.

if err := tmpl.Execute(&buff, &f); err != nil {
    panic(err)
}

. Или вы можете сделать это, передав указатель на EmailAddress.

type emailFormatter struct {
    From *EmailAddress
    To   *EmailAddress
}

// ...

f := emailFormatter{
    To:   &to,
    From: &from,
}

// ...

if err := tmpl.Execute(&buff, f); err != nil {
    panic(err)
}

или передавуказатель на mail.Address.

type EmailAddress struct{ *mail.Address }

// ...

to := EmailAddress{
    &mail.Address{
        Address: "em@i.l",
        Name: "",
    },
}
from := EmailAddress{
    &mail.Address{
        Address: "no-reply@test.quest",
        Name: "",
    },
}

f := emailFormatter{
    To:   to,
    From: from,
}

// ...

if err := tmpl.Execute(&buff, f); err != nil {
    panic(err)
}

Обратите внимание, что причина, по которой вам не нужно делать это в коде Go, заключается в том, что компилятор делает это за вас.

Например:

fmt.Println(to.String())

становится:

fmt.Println((&to).String())

Вызов метода xm () действителен, если набор методов (тип) x содержит m и аргументсписок может быть назначен на список параметров м. Если x адресуемый и набор методов & x содержит m, xm () является сокращением для (& x) .m ()

...