备注:

文章转自:https://www.djm.org.uk/posts/writing-extensible-elixir-with-behaviours-adapters-pluggable-backends/

This article also offers an intro to the Keyword List type in Elixir; non-beginners can almost certainly skip to the last section.

An intro to Elixir's Keyword Lists

Keyword lists in Elixir are simply a special case of a list, their contents being made up entirely of 2-item "pair" tuples with the first item of each being an Elixir :atom. Unlike maps, they are ordered and may contain multiple values for the same key. Due to their prevalence in the language, a lot of syntactic sugar has been created to make working with them easier and more idiomatic. For example, during creation:

iex(1)> [{:cats, 2}, {:dogs, 1}] == [cats: 2, dogs: 1]
true

You can see that the two ways of defining them are one and the same, the one on the right obviously being the syntactically sugared version.

Passing an optional set of options to a function

Other than creating small k:v stores, this is their primary use case in both Elixir & Erlang. By allowing a client to pass in a keyword list full of options, the function can conditionally change its logic. The keyword list is commonly optional and passed as the last parameter, so common in fact that Elixir has provided more syntactic sugar which allows you to leave off the keyword lists square brackets when it is being passed as the last parameter. For example:

def func_with_options(arg1, opts \\ []) do
# ...
end

..and the function can be called as follows:

# With no options at all..
func_with_options("arg1")
# With options, the non-sugared way.
func_with_options("arg1", [verbose: true, indent: 4])
# With options, with syntactic sugar.
func_with_options("arg1", verbose: true, indent: 4)

Note that in the last instance the function signature is still func_with_options/2; despite the keyword list having 2 elements they are contained inside one list, the arity of the function does not change.

And that leads us on to the main point of this article: what if a function accepts only one parameter and it is a keyword list?

Retrieving the same return for different input

I'm sure there is a much better way of putting that but I do currently know it; this is better showcased by an example. First, let's set the scene:

You have user account functionality in your app and the record for each user contains, amongst others, the fields: username, email & ni_number; the user's username, email address, and National Insurance number respectively - all unique, indexed and all strings. You'd like to create some form of a shortcut to retrieve a user record from your data store using any of the aforementioned fields; as they are all unique to the user, only one is required to get a hit.

In quite a few languages, we suffer a problem here as all 3 lookups are string based, we therefore cannot rely on type to allow our helper function to do different things based on the input. If it was just username & email perhaps we could do a check to see if the string contains an '@' sign but that would be a flimsy solution at best, and completely falls apart when we also want to allow lookup by ni_number which like username, is just an alphanumerical string. Thus, a solution to this that I have often seen in various languages is multiple helper methods:

# Pseudo-code
get_user_by_username("harry")
get_user_by_email("harry@example.com")
get_user_by_ni_number("JN032185D") # or even:
User.get_by_username("harry")
User.get_by_email("harry@example.com")
User.get_by_ni_number("JN032185D")

Fine, both ways get the job done but that is about all you can say about them.

In Python, another common pattern is to pass keyword arguments as a form of lookup dictionary:

def get_user(**lookup):
return SomeORM.get(**lookup) get_user(username="harry")
get_user(email="harry@example.com")
get_user(ni_number="JN032185D")

Which is an improvement but in this instance it tightly couples the logic of your wrapper with that of the ORM or underlying data store, as the client must know the field names or the lookup dict might even have a special format (e.g Django's fieldname__iexact lookup filters). This makes the wrapper less useful from an abstraction perspective.

Now, back to Elixir. As we've already said, when the last parameter to a function is a keyword list, you can leave off the square brackets; this also applies when the parameter is also the first and only one. Therefore we can combine multiple function clauses with Elixir's pattern matching to allow:

  • the handling code to split up the differing lookups without using conditional logic. Our brains are not perfect at following conditional branches, following linear code is much less bug-prone.
  • our clients to have a nice API, where they simply hint at the type of lookup they wish for.
defmodule User do

  def get(username: username) do
# Do lookup with username
end def get(email: email) do
# Do lookup with email
end def get(ni_number: ni_number) do
# Do lookup with ni_number
end end # Which gives us a the following API..
User.get(username: "harry")
User.get(email: "harry@example.com")
User.get(ni_number: "JN032185D")

And that is the power that can be achieved by combining multiple function clauses with pattern matching. As with any powerful thing, it will be likely be abused - so only use this pattern in cases where it completely makes sense: if in doubt, multiple parameters to a function is the normal way to go.

This pattern is in fact already in use in the code powering hex.pm; you can see the code base over at the hex_web repository on github.

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

 
 
 
 

Elixir's keyword lists as option parameters的更多相关文章

  1. EBS initialization parameters - Healthcheck

    APPLIES TO: Oracle EBS Applications Performance - Version 11.5.10.2 to 12.2 [Release 11.5.10 to 12.2 ...

  2. CentOS 7.7安装Erlang和Elixir

    安装之前,先看一下它们的简要说明 Erlang Erlang是一种开源编程语言,用于构建对高可用性有要求的大规模可扩展的软实时系统.它通常用于电信,银行,电子商务,计算机电话和即时消息中.Erlang ...

  3. 关于netty配置的理解serverBootstrap.option和serverBootstrap.childOption

    The parameters that we set using ServerBootStrap.option apply to the ChannelConfig of a newly create ...

  4. PHP Redis 全部操作方法

    Classes and methods Usage Class Redis Class RedisException Predefined constants Class Redis Descript ...

  5. Oracle管理文件OMF (oracle managed files)

    简化dba的管理操作 1:启用 omf 23:16:04 SYS@orcl> show parameter DB_CREATE_FILE_DEST NAME TYPE VALUE ------- ...

  6. Sphinx 2.2.11-release reference manual

    1. Introduction 1.1. About 1.2. Sphinx features 1.3. Where to get Sphinx 1.4. License 1.5. Credits 1 ...

  7. PHP Redis 全部操作方法 转载

    PHP Redis 全部操作方法   Classes and methods Usage Class Redis Class RedisException Predefined constants C ...

  8. acedSSGet 翻译

    ObjectARX 参考指南 > 全局函数 > AcEd 全局函数 > acedSSGet 函数 acedSSGet 折叠全部 C++ int acedSSGet( const AC ...

  9. PHP-redis英文文档

    作为程序员,看英文文档是必备技能,所以尽量还是多看英文版的^^ PhpRedis The phpredis extension provides an API for communicating wi ...

随机推荐

  1. IntelliJ IDEA 返回上次编辑(鼠标停留)的地方

    idea默认的是 : Ctrl + Alt + 左箭头,与笔记本的 旋转屏幕冲突: 找到: 我更改成了: Ctrl + CapsLock :暂时没发现冲突.

  2. Highcharts 时间序列,可缩放的图表;Highcharts X 轴翻转曲线图;Highcharts 带标记曲线图

    Highcharts 时间序列,可缩放的图表 配置 图表 配置可缩放图表. chart.zoomType 指定了用户可以拖放的尺寸,用户可以通过拖动鼠标来放大,可能值是x,y或xy: var char ...

  3. 快速切题 poj 1003 hangover 数学观察 难度:0

    Hangover Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 103896   Accepted: 50542 Descr ...

  4. Prism 4 文档 ---第2章:初始化Prism应用程序

     这一章节介绍Prism应用程序启动和运行时发生的内容.Prism应用程序在启动时需要有注册和配置的过程,这就是所谓的自自启动程序. 什么是自启动引导程序?     引导程序是一个类,它负责使用Pri ...

  5. Win10 怎么给php文件设置默认打开应用

    一,首先以管理员身份打开命令提示符 二,assoc .php=phpfile 创建一个文件关联 三,ftype phpfile="E:\Program Files\Sublime Text ...

  6. 老鼠走迷宫(1)输出唯一路径(C语言)

    需求 有一个迷宫,在迷宫的某个出口放着一块奶酪.将一只老鼠由某个入口处放进去,它必须穿过迷宫,找到奶酪.请找出它的行走路径. STEP 1 题目转化 我们用一个二维数组来表示迷宫,用2表示迷宫的墙壁, ...

  7. iOS实现程序长时间未操作退出

    大部分银行客户端都有这样的需求,在用户一定时间内未操作,即认定为token失效,但未操作是任何判定的呢?我的想法是用户未进行任何touch时间,原理就是监听runloop事件.我们需要进行的操作是创建 ...

  8. 关于$_SERVER['PHP_AUTH_USER']

    http://www.cnblogs.com/thinksasa/p/3421379.html PHP 的 HTTP 认证机制仅在 PHP 以 Apache 模块方式运行时才有效,因此该功能不适用于 ...

  9. Android敏捷开发、CI(持续集成)探究

    比较老的几篇文章,依旧有学习价值 http://blog.csdn.net/baodinglaolang/article/details/9530695 http://blog.csdn.net/ba ...

  10. 如何制作dll库的API文档,自动生成微软风格的chm文件 Sandcastle Help File Builder 使用方法

    当你开发了一个库的时候,就需要给库开发一个api文档,微软提供了一个C#库的自动生成工具.我在使用的过程中记录了相关的信息,以供大家学习和查阅,如有不正之处,欢迎指出. 首先先下载一个软件,下载地址在 ...