做&不要写精富的
#编程 #教程 #python #elixir

在本文中,我们将探索do and do and not of撰写elixir代码。我们将简要了解从其他语言转换为长生不老药的关键挑战。为简单起见,我们将使用Python&Elixir编写所有示例和代码片段,并学习一些程序员在从其他编程语言中切换到Elixir时经常遇到的常见错误。

什么是长生不老药?

长生不老药是一种功能性进程语言,可在强大的ERLANG VM上运行。 Elixir充分利用了VM,并为开发人员提供了完美的环境,以构建容忍,低延迟,分布式系统。

根据Stackoverflow的2022年开发人员调查,这是年度第二个most loved Programming language

长生不老家社区正在增长,随着越来越多的人和公司采用长生不老药的代码基础。

切换到长生不老药的主要挑战

与其他功能编程语言(例如Erlang,Clojure等)不同。LEXIXIR具有更具初学者的语法。这也为将其他编程语言的行李带到Elixir。

例如,没有以前的功能编程经验的Python程序员可能会尝试应用不适合功能编程的对象编程的编码模式。即使,他们可能会逃脱写的代码,这些代码比“ elixir”更“ Pythonic”。从长远来看,这将阻碍他们的增长和生产力。

缺乏功能编程知识也将阻止他们利用各种功能编程范例。它还将在至少三个不同的层中挑战他们的核心概念:

  1. 功能性思维方式(即不变性/流/转换/管道)
  2. OTP思维方式(即并发,耐故障,分布式系统)
  3. 图案和管道。

因此,他们将不得不从新鲜的角度学习他们已经知道和思考的内容。这一初步步骤相对较难,但是一次,他们掌握了它们将立即变得富有成效的概念。

现在让我们看看一些示例:

可变与不变

在Python环境中,变量或物体可变。考虑以下代码段:

my_list = [1, 2, 3, 4]
do_something(my_list)
print(my_list)

在这里,我们不能可靠地说,如果不查看函数do_something的源代码,则打印语句的输出将是什么。在Python中,列表作为参考传递,因此do_something函数可能可以更改原始my_list,例如在列表中添加一些东西或删除一两件事。如果我们认为并行或并行编程,这可能会导致意想不到的错误。访问同一对象的两个进程可以根据执行顺序或力矩获取不同的值。

在长生不老药中,这不是问题,变量总是不变的:

my_list = [1, 2, 3]
do_something(my_list)
IO.inspect(my_list)

在这里,IO.inspect()的输出保证可以获取列表[1, 2, 3]。换句话说,do_something()函数无法修改my_list变量。即使我们产生数百或数千个流程并访问my_list,所有这些过程都将获得相同的my_list值。对于复杂数据(例如嵌套列表,地图或数据库记录等)等复杂数据也是如此。

掌握不变性的概念对于编写好的精灵代码至关重要。

嵌套功能调用与管道

嵌套功能调用在大多数编程语言中都是常见的。当我们想将函数的返回值传递为嵌套发生的另一个函数的agrument时。这更像是一系列对数据的转换。 Elixir还允许嵌套功能调用转换数据。考虑以下示例:

decorate(bake(add_flavor(mix(ingredients))))

您将不得不花一些时间仔细阅读该声明,并弄清楚哪个函数在哪个序列中得到了什么影响。而且,数据如何在每个步骤中转换。

幸运的是,Elixir通过引入一个名为“ Pipe”(|>)的新操作员来优雅地解决这个问题。它将表达式的结果归功于其左/顶部,并将其作为函数调用的第一个参数插入右/底部。使用管道操作员,我们可以重写上面的示例:

ingredients
|> mix()
|> add_flavor()
|> bake()
|> decorate()

在这里,函数调用的步骤和顺序很清楚。我们将ingredients传递给mix()mix()的结果被管道到add_flavor()。然后我们bake()结果,最后我们decorate()

底线是,请勿使用嵌套功能调用编写长生不老药代码,而是使用管道。这将使您的代码清晰,简洁且更具可读性。

功能和模式匹配

模式匹配是长生不老药编程语言中最强大的功能之一。掌握模式匹配技术将提高生产力并提高代码质量。关键是要知道何时何地可以应用模式匹配。让我们探索以下python函数:


def flip(coin):
    if coin == "head":
        return "tail"
    elif coin == "tail":
        return "head"
    else:
        return "invalid"

此功能只需翻转硬币。如果硬币是head,它将返回tail,反之亦然。它还返回invalid的任何其他参数。现在,如果我们愿意,我们可以在长生不老药中以类似的方式编写它:

def flip(coin) do
    if coin == "head" do
        "tail"
    else
        if coin == "tail" do
            "head"
        else
            "invalid"
        end
    end
end

这个肯定有效,但看起来不好。首先,它具有一个嵌套的if...else块。每当您注意到您的代码已嵌套块时,请花几点时间思考一下。必须有更好的方法。在上述情况下,我们确实有更好的方法来实现相同的功能。我们可以使用3条简单的代码来重构此代码:

def flip("head"), do: "tail"
def flip("tail"), do: "head"
def filp(_), do: "invalid"

看起来很整洁,不是吗?我们正在使用模式匹配来直接从函数参数匹配参数。当调用函数flip时,elixir将采用每种方法签名,并将其与输入参数匹配。比赛发生后,它将执行功能并停止。因此,例如,如果我们将参数“尾巴”称为flip函数。 Elixir将首先尝试将参数与第一个函数匹配一次,它将失败,它将移至下一个函数。由于第二个功能将“尾巴”作为参数,因此将被执行。我们将获得输出“头”。

它也适用于复杂的数据结构,例如字典或地图。例如,请参见下面的函数,该函数将字典person作为参数并打印全名。

def get_fullname(person):
    firstname = person.get("firstname") 
    lastname = person.get("lastname")
    return f"{firstname} {lastname}"

dict person具有两个键值对,firstnamelastname。我们首先从dict中检索值并将其存储在两个变量中,然后我们通过使用F-Scring将它们串联来打印它们。

在长生不老药中,我们可以在函数签名中进行模式匹配:


def get_fullname(%{firstname: first_name, lastname: last_name}) do
    "#{first_name} #{last_name}"
end

就像dict Elixir具有一个名为MAP的数据结构,我们在此示例中使用了映射。 firstnamelastname是原子,它们是地图的关键。 first_namelast_name变量将使用模式匹配获得地图的值。而且,在功能主体中,我们只返回串联的字符串。

上面的示例非常基本,但是它们使我们了解了模式匹配的工作方式。而且,它如何帮助我们改善质代码。

结论

在将其称为一天之前,让我们快速回顾到目前为止我们已经探索的内容。我们了解了从不同的编程语言转换为长生不老药的关键挑战。我们还探索了一些常见的错误,以及如何利用长生不老药和最佳实践来避免它们。