使用结构体建模服务器端点时遇到问题 - Golang求助
使用结构体建模服务器端点时遇到问题 - Golang求助 你认为这是一种合理的服务器端点建模方式吗?基本上,我有一个通用的端点,但希望根据负载进行特化。这对我来说似乎有点冗长,尤其是在访问结构体字段时。
package main
import (
"fmt"
)
type Endpoint struct {
NeedsAuthentication bool
Uri string
}
type RefreshEndpoint struct {
Endpoint
Payload RefreshPayload
}
type RefreshPayload struct {
RefreshToken string
}
func main() {
refreshEndpoint := RefreshEndpoint{Endpoint: Endpoint{NeedsAuthentication: true, Uri: "/foo"}, Payload: RefreshPayload{RefreshToken: "xxx"}}
fmt.Printf("The uri is: %s, the access token is: %s", refreshEndpoint.Endpoint.Uri, refreshEndpoint.Payload.RefreshToken)
}
解决 refreshEndpoint.Endpoint.Uri 这种奇怪的间接访问的一种方法是在 RefreshEndpoint 上定义一个名为 Uri 的方法:
package main
import (
"fmt"
)
type Endpoint struct {
NeedsAuthentication bool
Uri string
}
type RefreshEndpoint struct {
Endpoint
Payload RefreshPayload
}
type RefreshPayload struct {
RefreshToken string
}
func (e RefreshEndpoint) Uri() string {
return e.Endpoint.Uri
}
func main() {
refreshEndpoint := RefreshEndpoint{Endpoint: Endpoint{NeedsAuthentication: true, Uri: "/foo"}, Payload: RefreshPayload{RefreshToken: "xxx"}}
fmt.Printf("The uri is: %s, the access token is: %s", refreshEndpoint.Uri(), refreshEndpoint.Payload.RefreshToken)
}
这样我们就可以像 refreshEndpoint.Uri() 这样访问 URI。
但问题依然存在。如何优雅地建模一个通用的 Endpoint,使其能够根据端点类型接收不同类型的负载?
更多关于使用结构体建模服务器端点时遇到问题 - Golang求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
我发现,由于 RefreshEndpoint 嵌入了 Uri,我可以直接访问它。我之前没有意识到这一点。
更多关于使用结构体建模服务器端点时遇到问题 - Golang求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个合理的建模方式,但可以通过接口和泛型来改进。以下是两种更优雅的解决方案:
方案一:使用接口和类型断言
package main
import (
"fmt"
)
type Endpoint struct {
NeedsAuthentication bool
Uri string
Payload interface{}
}
type RefreshPayload struct {
RefreshToken string
}
type LoginPayload struct {
Username string
Password string
}
func (e Endpoint) GetRefreshPayload() (RefreshPayload, bool) {
payload, ok := e.Payload.(RefreshPayload)
return payload, ok
}
func (e Endpoint) GetLoginPayload() (LoginPayload, bool) {
payload, ok := e.Payload.(LoginPayload)
return payload, ok
}
func main() {
refreshEndpoint := Endpoint{
NeedsAuthentication: false,
Uri: "/refresh",
Payload: RefreshPayload{RefreshToken: "xxx"},
}
loginEndpoint := Endpoint{
NeedsAuthentication: false,
Uri: "/login",
Payload: LoginPayload{Username: "user", Password: "pass"},
}
if payload, ok := refreshEndpoint.GetRefreshPayload(); ok {
fmt.Printf("URI: %s, RefreshToken: %s\n", refreshEndpoint.Uri, payload.RefreshToken)
}
if payload, ok := loginEndpoint.GetLoginPayload(); ok {
fmt.Printf("URI: %s, Username: %s\n", loginEndpoint.Uri, payload.Username)
}
}
方案二:使用Go 1.18+泛型(推荐)
package main
import (
"fmt"
)
type Endpoint[T any] struct {
NeedsAuthentication bool
Uri string
Payload T
}
type RefreshPayload struct {
RefreshToken string
}
type LoginPayload struct {
Username string
Password string
}
// 泛型处理器示例
func HandleEndpoint[T any](endpoint Endpoint[T]) {
fmt.Printf("处理端点: %s\n", endpoint.Uri)
fmt.Printf("需要认证: %v\n", endpoint.NeedsAuthentication)
// 可以直接访问特定类型的Payload
_ = endpoint.Payload
}
// 类型特定的处理
func HandleRefresh(endpoint Endpoint[RefreshPayload]) {
fmt.Printf("刷新令牌: %s\n", endpoint.Payload.RefreshToken)
}
func HandleLogin(endpoint Endpoint[LoginPayload]) {
fmt.Printf("用户名: %s\n", endpoint.Payload.Username)
}
func main() {
refreshEndpoint := Endpoint[RefreshPayload]{
NeedsAuthentication: false,
Uri: "/refresh",
Payload: RefreshPayload{RefreshToken: "xxx"},
}
loginEndpoint := Endpoint[LoginPayload]{
NeedsAuthentication: false,
Uri: "/login",
Payload: LoginPayload{Username: "user", Password: "pass"},
}
// 直接访问,无需嵌套
fmt.Printf("刷新端点URI: %s, 令牌: %s\n",
refreshEndpoint.Uri,
refreshEndpoint.Payload.RefreshToken)
fmt.Printf("登录端点URI: %s, 用户: %s\n",
loginEndpoint.Uri,
loginEndpoint.Payload.Username)
// 使用泛型处理器
HandleEndpoint(refreshEndpoint)
HandleEndpoint(loginEndpoint)
// 使用类型特定处理器
HandleRefresh(refreshEndpoint)
HandleLogin(loginEndpoint)
}
方案三:组合方法提升
package main
import (
"fmt"
)
type Endpoint struct {
NeedsAuthentication bool
Uri string
}
type RefreshEndpoint struct {
Endpoint
Payload RefreshPayload
}
type LoginEndpoint struct {
Endpoint
Payload LoginPayload
}
type RefreshPayload struct {
RefreshToken string
}
type LoginPayload struct {
Username string
Password string
}
// 为所有嵌入Endpoint的结构体提供统一访问
func (e Endpoint) GetURI() string {
return e.Uri
}
func (e Endpoint) NeedsAuth() bool {
return e.NeedsAuthentication
}
// 类型特定的方法
func (e RefreshEndpoint) GetRefreshToken() string {
return e.Payload.RefreshToken
}
func (e LoginEndpoint) GetCredentials() (string, string) {
return e.Payload.Username, e.Payload.Password
}
func main() {
refreshEndpoint := RefreshEndpoint{
Endpoint: Endpoint{NeedsAuthentication: false, Uri: "/refresh"},
Payload: RefreshPayload{RefreshToken: "xxx"},
}
loginEndpoint := LoginEndpoint{
Endpoint: Endpoint{NeedsAuthentication: false, Uri: "/login"},
Payload: LoginPayload{Username: "user", Password: "pass"},
}
// 简洁的访问方式
fmt.Printf("刷新端点: %s, 令牌: %s\n",
refreshEndpoint.GetURI(),
refreshEndpoint.GetRefreshToken())
fmt.Printf("登录端点: %s, 用户: %s\n",
loginEndpoint.GetURI(),
loginEndpoint.Payload.Username)
// 统一处理不同端点的示例
endpoints := []interface{}{refreshEndpoint, loginEndpoint}
for _, ep := range endpoints {
switch e := ep.(type) {
case RefreshEndpoint:
fmt.Printf("处理刷新端点: %s\n", e.GetRefreshToken())
case LoginEndpoint:
user, _ := e.GetCredentials()
fmt.Printf("处理登录端点: %s\n", user)
}
}
}
泛型方案最简洁,它提供了类型安全且无需类型断言。如果使用Go 1.18+,推荐方案二;如果使用旧版本,方案三的组合方法提升是不错的选择。

