博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Elixir: 函数装饰器
阅读量:6701 次
发布时间:2019-06-25

本文共 1709 字,大约阅读时间需要 5 分钟。

Java 模式里面有一个概念叫「对修改关闭, 对扩展开放」, 这是一个面向对象的组件可重用原则. 装饰器就是实现该原则的一个经典实例.

装饰器原理

通过符号注解的方式, 给被注解的函数或对象添加新功能, 重写现有的功能, 而又不对现有的代码做变化的一种方法. 它对使用者是透明的. 通过装饰器可以实现的常用功能包括:

  • 访问控制

  • 计时器探针, 检测函数的运行时间

  • 日志记录

在Elixir中, 主要是对函数进行装饰. 一个函数装饰器是形似@decorate 的一个符号注解, 紧接着函数定义的上一行, 它可以用于给Elixir函数添加额外的功能. 函数装饰器运行时开销为0, 因为它是在编译时执行的.

装饰器以函数作为参数, 并且返回一个经过修改, 或添加了新功能的函数. 它是一个高阶函数.

defmodule MyModule do  use PrintDecorator  @decorate print()  def square(a) do    a * a  endend

函数装饰器实际上是Elixir宏.

Elixir 中的函数装饰器, 我们用到了 这个库.

装饰器的定义

定义装饰器是比较简单的, 创建一个模块, 并且在模块中 use Decorator.Define, [print: 0], 这样就定义了一个名称为print的装饰器了.

下面是一个装饰器的完整定义示例:

defmodule PrintDecorator do  # 声明装饰器的名号, 参数数量  use Decorator.Define, [print: 0]  # 实现装饰器  def print(body, context) do    quote do      IO.puts("Function called: " <> Atom.to_string(unquote(context.name)))      unquote(body)    end  endend

装饰器函数的参数(def print(...)) 为函数体(AST, 抽象语法树), 以及一个context参数, context 持有函数名称, 定义模块, 参数数量, 以及参数AST等信息.

编译时传参

装饰器可以进行编译时参数传递, 例如日志模块仅打印消息级别为:debug 的日志.

@decorate print(:debug)def foo() do...

对此, 需要修改装饰器模块的定义:

defmodule PrintDecorator do  use Decorator.Define, [print: 1]  def print(level, body, context) do  # ...  endend

装饰器上下文

除了传入装饰器函数的函数体AST, 装饰器函数还有一个传入的上下文参数 context, context 参数包含了函数调用的相关信息:

def print(body, context) do  Logger.debug("Function #{context.name}/#{context.arity} called in module #{context.module}!"end

上下文具体包含哪些东西, 可通过 IO.puts #{inspect context} 打印出来.

下面是一个有用的示例, 是一个Phoenix框架中用户检查用户认证的一个装饰器宏.

defmodule Auth do  def is_authorized(body, %{args: [conn, _params]}) do    quote do      if unquote(conn).assigns.user do        unquote(body)      else        unquote(conn)        |> send_resp(401, "unauthorized")        |> halt()      end    end  endend

~完 (^_^!)

转载地址:http://mpwlo.baihongyu.com/

你可能感兴趣的文章
汽车研发歌
查看>>
组策略之WMI筛选器: LIKE运算符
查看>>
2015年8月25日【用户管理各命令的使用】-JY1506402-19+liuhui880818
查看>>
我的友情链接
查看>>
我玩过的JS_无需整理
查看>>
Restart or shutdown the VM in Xen Server
查看>>
Centos7安装chrome浏览器
查看>>
第八章 磁盘操作-centos7.5知识
查看>>
libjpeg.(a|so)--libpng.(also)--ldap libraries
查看>>
Java Math.round()
查看>>
python 自动生成k8s 集群yaml 文件
查看>>
declare命令
查看>>
怎样用cmd启动停止服务
查看>>
CSS 很容易,那为什么大家还是把 CSS 写的那么烂呢?
查看>>
文件权限的s位
查看>>
zencart 如何调用边框等
查看>>
JS获取页面高宽
查看>>
Java集合, ArrayBlockingQueue源码解析(常用于并发编程)
查看>>
二维几何变换---二维复合变换
查看>>
阶乘的末尾有多少0 Factorial Trailing Zeroes
查看>>