Golang中如何根据参数选择特定功能
Golang中如何根据参数选择特定功能 你好,
我希望在运行时通过向一个“选择器”函数传递参数来选择特定的存储库。是的,这类似于面向对象编程中的策略模式。假设我有一个“选择器”函数/结构体,或者随便你怎么称呼它。当我传递 Account 结构体调用它时,我应该只能访问其方法,例如 Total()。如果我传递 User,则只能访问 FindNameByID(id int)。这在 Go 语言中可以实现吗?
我查看了 Go 策略模式,但我的结构体内部总是会有不同的函数。
谢谢
package repository
type User struct {
// Some field(s)
}
func (u User) FindNameByID(id int) string {
// Do something with u
users := map[int]string{1: "bob", 2: "jon"}
return users[id]
}
package repository
type Account struct {
// Some field(s)
}
func (a Account) Total() int {
// Do something with a
return 10
}
用法
ar := RepoSelector(Account{})
ar->Total()
ur := RepoSelector(User{})
ur->FindNameByID(1)
注意:如果可能的话,我希望不向 Account 和 User 传递字段参数,因此它们应该已经被注入。
更多关于Golang中如何根据参数选择特定功能的实战教程也可以访问 https://www.itying.com/category-94-b0.html
@skillian 你误解了重点,纠结于函数可能做什么,这与问题本身无关。
更多关于Golang中如何根据参数选择特定功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感谢您的回答。然而,您的解决方案违背了我“唯一”的要求,即按接收者隔离函数,因此如果我获取 User,应该只看到 FindNameByID(),而不是 Total()。
谢谢 @adriel
你的解决方案也是我某个时刻想到过的,但你可能已经猜到,随着事情发展,它可能会很快变得非常混乱。我可能会重新考虑我的想法,因为到目前为止我还没有找到一个清晰的解决方案。不过还是谢谢你的建议。
我对你的示例有些困惑。看起来,当你获取一个 User 时,你希望将其视为某种可以通过 ID 查找的 User 存储库,但当你获取一个 Account 时,你得到的是一个特定账户的 Total。那么,User 是获取一个特定的 User 还是一个存储库?Account 是获取一个账户还是一个存储库?
你好 @GoingToGo,
如果你使用策略模式,你应该在你的接口中定义你的方法。假设你的接口是:
type RepoSelector interface {
FindNameByID(int)
Total() int
}
因此,当你在 RepoSelector 接口中定义方法时,你的结构体必须能够访问这两个方法 FindNameByID(int) 和 Total() int。例如,对于 Account 和 User:
type User struct {}
func (u User) Total()int {}
func (u User) FindNameByID(int){}
type Account struct {}
func (a Account) Total()int {}
func (a Account) FindNameByID(int){}
对我来说,使用单一接口来隔离方法是不可能的。不过,我写了一段简单的代码,尝试通过两个接口来隔离函数。
type SelectorA interface {
FindNameByID(int)
}
type SelectorB interface {
Total() int
}
type Operation struct {}
func NewOperation(m interface{}) interface{} {`
switch v := m.(type) {
case SelectorA:
log.Println("[ SelectorA ]",v)
return v
case SelectorB:
log.Println("[ SelectorB ]",v)
return v
default:
log.Println("Unknown interface")
}
return nil
}
type User struct {}
func (a User) FindNameByID(n int) {
log.Println("user:",n)
}
type Account struct {}
func (a Account) Total() int {
return 10
}
func main() {
me := NewOperation(User{}).(User) // 作为 User 类型,因为它是接口
me.FindNameByID(34)
n := NewOperation(Account{}).(Account)
log.Println("Total:",n.Total())
}
在Go中可以通过接口和类型断言实现运行时根据参数选择特定功能。以下是几种实现方式:
方法一:使用接口和类型断言
package main
import "fmt"
// 定义接口
type Repository interface{}
// 具体类型
type User struct{}
func (u User) FindNameByID(id int) string {
users := map[int]string{1: "bob", 2: "jon"}
return users[id]
}
type Account struct{}
func (a Account) Total() int {
return 10
}
// 选择器函数
func RepoSelector(repo Repository) interface{} {
return repo
}
func main() {
// 使用类型断言调用特定方法
ar := RepoSelector(Account{})
if acc, ok := ar.(Account); ok {
fmt.Println("Account Total:", acc.Total())
}
ur := RepoSelector(User{})
if user, ok := ur.(User); ok {
fmt.Println("User Name:", user.FindNameByID(1))
}
}
方法二:使用函数返回具体类型
package main
import "fmt"
type User struct{}
func (u User) FindNameByID(id int) string {
users := map[int]string{1: "bob", 2: "jon"}
return users[id]
}
type Account struct{}
func (a Account) Total() int {
return 10
}
// 选择器函数返回具体类型
func RepoSelector(repo interface{}) interface{} {
return repo
}
// 包装函数提供类型安全调用
func UseAccount() {
ar := RepoSelector(Account{}).(Account)
fmt.Println("Account Total:", ar.Total())
}
func UseUser() {
ur := RepoSelector(User{}).(User)
fmt.Println("User Name:", ur.FindNameByID(1))
}
func main() {
UseAccount()
UseUser()
}
方法三:使用泛型(Go 1.18+)
package main
import "fmt"
type User struct{}
func (u User) FindNameByID(id int) string {
users := map[int]string{1: "bob", 2: "jon"}
return users[id]
}
type Account struct{}
func (a Account) Total() int {
return 10
}
// 泛型选择器
func RepoSelector[T any](repo T) T {
return repo
}
func main() {
// 类型安全的调用
ar := RepoSelector(Account{})
fmt.Println("Account Total:", ar.Total())
ur := RepoSelector(User{})
fmt.Println("User Name:", ur.FindNameByID(1))
}
方法四:工厂模式实现
package main
import "fmt"
type Repository interface {
Execute() interface{}
}
type User struct{}
func (u User) FindNameByID(id int) string {
users := map[int]string{1: "bob", 2: "jon"}
return users[id]
}
func (u User) Execute() interface{} {
return u.FindNameByID(1)
}
type Account struct{}
func (a Account) Total() int {
return 10
}
func (a Account) Execute() interface{} {
return a.Total()
}
// 工厂函数
func RepoSelector(repo Repository) interface{} {
return repo.Execute()
}
func main() {
ar := RepoSelector(Account{})
fmt.Println("Account Total:", ar)
ur := RepoSelector(User{})
fmt.Println("User Name:", ur)
}
方法五:使用闭包和函数类型
package main
import "fmt"
type User struct{}
func (u User) FindNameByID(id int) string {
users := map[int]string{1: "bob", 2: "jon"}
return users[id]
}
type Account struct{}
func (a Account) Total() int {
return 10
}
// 定义函数类型
type RepoFunc func() interface{}
// 选择器返回闭包
func RepoSelector(repo interface{}) RepoFunc {
switch r := repo.(type) {
case Account:
return func() interface{} {
return r.Total()
}
case User:
return func() interface{} {
return r.FindNameByID(1)
}
default:
return func() interface{} {
return nil
}
}
}
func main() {
ar := RepoSelector(Account{})
fmt.Println("Account Total:", ar())
ur := RepoSelector(User{})
fmt.Println("User Name:", ur())
}
推荐使用方法三的泛型实现,它提供了类型安全且简洁的语法。如果使用Go 1.18之前的版本,方法一的类型断言是常用方式。

