• 2.11 Go接口内部实现


    2.11 Go接口内部实现

    作用

    主要是处理数学当中的函数,根据函数画出函数表达的三维立体图片

    示例代码

    package main

    /* 创建一个算术表达式接口 */
    type Expr interface {

    }

    /* 声明可能的数据类型 */
    // Var表示一个变量。如:x
    type Var string

    // literal表示数字常量。如:3.14
    type literal float64

    // unary表示一元操作符表达式。如:-x
    type unary struct {
       op rune // "+","-"中的一个
       x Expr
    }

    // binary表示二元操作符表达式。如:x+y
    type binary struct {
       op rune // "+","-","*","/"中的一个
       x, y Expr
    }

    // call表示函数调用表达式
    type call struct {
       fn string // pow\sin\sqrt函数中的一个
       args []Expr
    }

    对包含变量的表达式进行求值,需要一个上下文 (environment) 来把变量映射到数值:

    // 添加上下文把变量映射到数值
    type Env map[Var]float64

    让每个表达式提供一个方法来返回表达式在一个给定上下文下的值(因为每个表达式都需要返回所以定义在接口当中):

    /* 创建一个算术表达式接口 */
    type Expr interface {
       // 每个表达式都必须都需要返回,所以在接口当中定义该方法
       Eval(env Env)float64
    }

    具体的Eval方法。VarEval方法从上下文中查询结果,如果变量不存在则返回0 literalEval方法则直接返冋本身的值:

    // Var和Eval类型的数据实现接口当中的方法
    func (v Var) Eval(env Env) float64 {
       return env[v]
    }

    func (l literal) Eval(env Env) float64 {
       return float64(l)
    }

    unarybinaryEval方法首先对它们的操作数递归求值,然后应用op操作。不把除以 0 或者无穷大当做错误:

    // `unary`和`binary`的`Eval`方法首先对它们的操作数递归求值,然后应用`op`操作。不把除以 0 或者无穷大当做错误
    func (u unary) Eval(env Env) float64 {
       // switch进行类型断言
       switch u.op {
       case '+':
           return +u.x.Eval(env)
       case '-':
           return -u.x.Eval(env)
      }

       // 抛出异常
       panic(fmt.Sprintf("不支持的操作:%q", u.op))
    }

    func (b binary) Eval(env Env) float64 {
       // 进行类型断言
       switch b.op {
       case '+':
           return b.x.Eval(env) + b.y.Eval(env)
       case '-':
           return b.x.Eval(env) - b.y.Eval(env)
       case '*':
           return b.x.Eval(env) * b.y.Eval(env)
       case '/':
           return b.x.Eval(env) / b.y.Eval(env)
      }

       // 抛出异常
       panic(fmt.Sprintf("不支持的流操作:%q", b.op))
    }

    call方法先对powsin或者sqrt函数的参数求值,再调用math包中的对应函数:

    // `call`方法先对`pow`、`sin`或者`sqrt`函数的参数求值,再调用`math`包中的对应函数
    func (c call) Eval(env Env) float64 {
       switch c.fn {
       case "pow":
           return math.Pow(c.args[0].Eval(env), c.args[1].Eval(env))
       case "sin":
           return math.Sin(c.args[0].Eval(env))
       case "sqrt":
           return math.Sqrt(c.args[0].Eval(env))
      }

       // 抛出异常
       panic(fmt.Sprintf("不支持的呼叫方法:%s", c.fn))
    }
    /*
    call 表达式可能会遇到未知的函数,或者参数数量不对。也有可能用“!”或者“<”这类无效的操作符构造了一个 unary 或 binary 表达式
    */

    整体代码

    package main

    import (
       "fmt"
       "math"
    )

    /* 创建一个算术表达式接口 */
    type Expr interface {
       // 每个表达式都必须都需要返回,所以在接口当中定义该方法
       Eval(env Env)float64
    }

    /* 声明可能的数据类型 */
    // Var表示一个变量。如:x
    type Var string

    // literal表示数字常量。如:3.14
    type literal float64

    // unary表示一元操作符表达式。如:-x
    type unary struct {
       op rune // "+","-"中的一个
       x Expr
    }

    // binary表示二元操作符表达式。如:x+y
    type binary struct {
       op rune // "+","-","*","/"中的一个
       x, y Expr
    }

    // call表示函数调用表达式
    type call struct {
       fn string // pow\sin\sqrt函数中的一个
       args []Expr
    }

    // 添加上下文把变量映射到数值
    type Env map[Var]float64

    // Var和Eval类型的数据实现接口当中的方法
    func (v Var) Eval(env Env) float64 {
       return env[v]
    }

    func (l literal) Eval(env Env) float64 {
       return float64(l)
    }

    // `unary`和`binary`的`Eval`方法首先对它们的操作数递归求值,然后应用`op`操作。不把除以 0 或者无穷大当做错误
    func (u unary) Eval(env Env) float64 {
       // switch进行类型断言
       switch u.op {
       case '+':
           return +u.x.Eval(env)
       case '-':
           return -u.x.Eval(env)
      }

       // 抛出异常
       panic(fmt.Sprintf("不支持的操作:%q", u.op))
    }

    func (b binary) Eval(env Env) float64 {
       // 进行类型断言
       switch b.op {
       case '+':
           return b.x.Eval(env) + b.y.Eval(env)
       case '-':
           return b.x.Eval(env) - b.y.Eval(env)
       case '*':
           return b.x.Eval(env) * b.y.Eval(env)
       case '/':
           return b.x.Eval(env) / b.y.Eval(env)
      }

       // 抛出异常
       panic(fmt.Sprintf("不支持的流操作:%q", b.op))
    }

    // `call`方法先对`pow`、`sin`或者`sqrt`函数的参数求值,再调用`math`包中的对应函数
    func (c call) Eval(env Env) float64 {
       switch c.fn {
       case "pow":
           return math.Pow(c.args[0].Eval(env), c.args[1].Eval(env))
       case "sin":
           return math.Sin(c.args[0].Eval(env))
       case "sqrt":
           return math.Sqrt(c.args[0].Eval(env))
      }

       // 抛出异常
       panic(fmt.Sprintf("不支持的呼叫方法:%s", c.fn))
    }

     

  • 相关阅读:
    观察者模式
    hdu 4712 Hamming Distance bfs
    leetcode Sum Root to Leaf Numbers(所有路径之和)
    Oracle实用-01:绑定变量
    jQuery实现AJAX定时刷新局部页面实例
    给Ajax一个漂亮的嫁衣——Ajax系列之五(下)之序列化和反序列化
    jquery的ajax同步和异步
    报表技术
    告别.NET生成报表统计图的烦恼
    浅谈ASP.NET报表控件
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/15944323.html
Copyright © 2020-2023  润新知