go里面的继承实现,父类类型做为函数入参,怎么传子类作为参数

lnktoking · 2023-08-31 17:53:35 · 2199 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2023-08-31 17:53:35 的主题,其中的信息可能已经有所发展或是发生改变。

type Task struct{
  TaskExec 
  Status int
  Name string
  StratTime int64
  EndTime int64
}

type TaskExec interface{
  exec()
}

type TaskA struct{
  Task
  ParamA string
}

type TaskB struct{
  Task
  ParamA string
}

func (TaskA) exec(){
  // 执行任务A的逻辑
}

func (TaskB) exec(){
  // 执行任务B的逻辑
}

// 执行任务,问题点在入参这里,这样写入参就只能是Task,不能传TaskA和TaskB,
// 用go有什么办法可以实现像java一样传子类做为入参
func Exec(task *Task){
  // 修改任务状态为执行中
  task.Status = 1
  // 记录任务开始执行时间
  task.StartTime = uint64(time.Now().Unix())
  // 这里还会有很共性逻辑处理被省略掉了

  // 执行具体任务的逻辑
  task.exec()
  // 修改任务状态为执行结束
  task.Status = 2
  // 记录任务执行结束时间
  task.EndTime = uint64(time.Now().Unix())
  // 这里也是还会有很共性逻辑处理被省略掉了
}

func main(){
  ta := TaskA{}
  tb := TaskB{}

  // 这里要怎么才能传子类到函数里面执行????
  Exec(&ta)
  Exec(&tb)
}

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2199 次点击  
加入收藏 微博
6 回复  |  直到 2023-09-04 20:29:58
yzbzg
yzbzg · #1 · 2年之前

或许这么写可以满足你的想法(公共逻辑可以绑定到父结构体Task上)

package main

import ( "log" "time" )

type Task struct { TaskExec Status int Name string StratTime int64 EndTime int64 }

func (t Task) start() { // 修改任务状态为执行中 t.Status = 1 // 记录任务开始执行时间 t.StratTime = time.Now().Unix() // 这里还会有很共性逻辑处理被省略掉了

}

func (t Task) end() { // 修改任务状态为执行结束 t.Status = 2 // 记录任务执行结束时间 t.EndTime = time.Now().Unix() }

type TaskExec interface { exec() }

type TaskA struct { Task ParamA string }

type TaskB struct { Task ParamA string }

func (a TaskA) exec() { // 执行任务A的逻辑 a.start() //A特有逻辑 log.Println("A特有逻辑") a.end()

}

func (b TaskB) exec() {

b.start()
//B特有逻辑
log.Println("B特有逻辑")
b.end()

}

// 执行任务,问题点在入参这里,这样写入参就只能是Task,不能传TaskA和TaskB, // 用go有什么办法可以实现像java一样传子类做为入参 func Exec(task TaskExec) {

// 这里也是还会有很共性逻辑处理被省略掉了
//具体逻辑
task.exec()

}

func main() { ta := TaskA{} tb := TaskB{}

// 这里要怎么才能传子类到函数里面执行????
Exec(&ta)
Exec(&tb)

}

GGXXLL
GGXXLL · #2 · 2年之前

你看这样会不会好点, Task 作为执行者,实际 exec 可以根据需求设置为实现 TaskExec 的对象。


type Task struct {
    exec      TaskExec
    Status    int
    Name      string
    StartTime int64
    EndTime   int64
}

func NewTask(exec TaskExec) *Task {
    return &Task{
        exec: exec,
    }
}

type TaskExec interface {
    exec()
}

type TaskA struct {
    ParamA string
}

type TaskB struct {
    ParamA string
}

func (TaskA) exec() {
    // 执行任务A的逻辑
}

func (TaskB) exec() {
    // 执行任务B的逻辑
}

// 执行任务,问题点在入参这里,这样写入参就只能是Task,不能传TaskA和TaskB,
// 用go有什么办法可以实现像java一样传子类做为入参
func (t *Task) Exec() {
    // 修改任务状态为执行中
    t.Status = 1
    // 记录任务开始执行时间
    t.StartTime = time.Now().Unix()
    // 这里还会有很共性逻辑处理被省略掉了

    // 执行具体任务的逻辑
    t.exec.exec()
    // 修改任务状态为执行结束
    t.Status = 2
    // 记录任务执行结束时间
    t.EndTime = time.Now().Unix()
    // 这里也是还会有很共性逻辑处理被省略掉了
}

func main() {
    ta := NewTask(&TaskA{})
    tb := NewTask(&TaskB{})

    // 这里要怎么才能传子类到函数里面执行????
    ta.Exec()
    tb.Exec()
}
lnktoking
lnktoking · #3 · 2年之前
yzbzgyzbzg #1 回复

或许这么写可以满足你的想法(公共逻辑可以绑定到父结构体Task上) package main import ( "log" "time" ) type Task struct { TaskExec Status int Name string StratTime int64 EndTime int64 } func (t Task) start() { // 修改任务状态为执行中 t.Status = 1 // 记录任务开始执行时间 t.StratTime = time.Now().Unix() // 这里还会有很共性逻辑处理被省略掉了 } func (t Task) end() { // 修改任务状态为执行结束 t.Status = 2 // 记录任务执行结束时间 t.EndTime = time.Now().Unix() } type TaskExec interface { exec() } type TaskA struct { Task ParamA string } type TaskB struct { Task ParamA string } func (a TaskA) exec() { // 执行任务A的逻辑 a.start() //A特有逻辑 log.Println("A特有逻辑") a.end() } func (b TaskB) exec() { b.start() //B特有逻辑 log.Println("B特有逻辑") b.end() } // 执行任务,问题点在入参这里,这样写入参就只能是Task,不能传TaskA和TaskB, // 用go有什么办法可以实现像java一样传子类做为入参 func Exec(task TaskExec) { // 这里也是还会有很共性逻辑处理被省略掉了 //具体逻辑 task.exec() } func main() { ta := TaskA{} tb := TaskB{} // 这里要怎么才能传子类到函数里面执行???? Exec(&ta) Exec(&tb) }

你这个接近我描述需要的要求,但我实际要实现逻辑要复杂一点,这里只是简化了。实际具体的任务逻辑还有几个函数要实现的,例如前置后置通知,异常通知等,你这样实现每个任务的执行方法都要重复这个代码逻辑,我大概要实现10来个任务,还是会有很多冗余代码,不过还是感谢回复

lnktoking
lnktoking · #4 · 2年之前
GGXXLLGGXXLL #2 回复

你看这样会不会好点, `Task` 作为执行者,实际 `exec` 可以根据需求设置为实现 `TaskExec` 的对象。 ``` type Task struct { exec TaskExec Status int Name string StartTime int64 EndTime int64 } func NewTask(exec TaskExec) *Task { return &Task{ exec: exec, } } type TaskExec interface { exec() } type TaskA struct { ParamA string } type TaskB struct { ParamA string } func (TaskA) exec() { // 执行任务A的逻辑 } func (TaskB) exec() { // 执行任务B的逻辑 } // 执行任务,问题点在入参这里,这样写入参就只能是Task,不能传TaskA和TaskB, // 用go有什么办法可以实现像java一样传子类做为入参 func (t *Task) Exec() { // 修改任务状态为执行中 t.Status = 1 // 记录任务开始执行时间 t.StartTime = time.Now().Unix() // 这里还会有很共性逻辑处理被省略掉了 // 执行具体任务的逻辑 t.exec.exec() // 修改任务状态为执行结束 t.Status = 2 // 记录任务执行结束时间 t.EndTime = time.Now().Unix() // 这里也是还会有很共性逻辑处理被省略掉了 } func main() { ta := NewTask(&TaskA{}) tb := NewTask(&TaskB{}) // 这里要怎么才能传子类到函数里面执行???? ta.Exec() tb.Exec() } ```

感谢回复,你这个基本达到了我的要求, 但在 NewTask 之后已经不是原来的对象,执行任务里面的逻辑改了任务状态不是原来任务对象的状态。就这里还有点问题,我顺着你的思路想想怎么搞

yzbzg
yzbzg · #5 · 2年之前

@lnktoking 嗯,go的多态一般是结合interface接口去实现,你可以顺着这个思路结合你实际的需求尝试尝试

symphony09
symphony09 · #6 · 2年之前

java 的上转型确实巧妙,回归正题,用 go 的话我会这样写

type ITask interface {
    TaskExec

    // 通过接口方法间接访问属性
    Info() *TaskInfo
}

type Task struct {
    TaskExec
    TaskInfo
}

func (task *Task) Info() *TaskInfo {
    return &task.TaskInfo
}

// 封装属性
type TaskInfo struct {
    Status    int
    Name      string
    StartTime uint64
    EndTime   uint64
}

type TaskExec interface {
    exec()
}

type TaskA struct {
    Task
    ParamA string
}

type TaskB struct {
    Task
    ParamA string
}

func (TaskA) exec() {
    // 执行任务A的逻辑
}

func (TaskB) exec() {
    // 执行任务B的逻辑
}

// 在 go 中用接口实现多态
func Exec(task ITask) {
    // 接口无法访问属性,通过 Info 方法间接访问
    // 修改任务状态为执行中
    task.Info().Status = 1
    // 记录任务开始执行时间
    task.Info().StartTime = uint64(time.Now().Unix())
    // 这里还会有很共性逻辑处理被省略掉了

    // 执行具体任务的逻辑
    task.exec()
    // 修改任务状态为执行结束
    task.Info().Status = 2
    // 记录任务执行结束时间
    task.Info().EndTime = uint64(time.Now().Unix())
    // 这里也是还会有很共性逻辑处理被省略掉了
}

func main() {
    ta := TaskA{}
    tb := TaskB{}

    // 嵌入 Task 的类型自动实现 ITask 接口,可以被传入 Exec 函数
    Exec(&ta)
    Exec(&tb)
}
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传