0

我正在为我的项目使用 {:guardian, "~> 1.0"} 来生成令牌,但它给了我一个错误。

这是我的监护人文件的代码

defmodule Dailyploy.Guardian do
  use Guardian, otp_app: :dailyploy

  def subject_for_token(user, _claims) do
    sub = to_string(user.id)
    {:ok, sub}
  end

  def subject_for_token(_, _) do
    {:error, :reason_for_error}
  end

  def resource_from_claims(claims) do
    id = claims["sub"]
    resource = Dailyploy.Accounts.get_user!(id)
    {:ok,  resource}
  end

  def resource_from_claims(_claims) do
    {:error, :reason_for_error}
  end
end

它向我显示了 subject_for_token 的错误。该子句无法匹配,因为第 4 行的前一个子句始终匹配Elixir

有人可以解释为什么它不起作用吗?

4

2 回答 2

1

编译器抱怨,因为你的两个定义subject_for_token是相同的,它们都期望完全相同的参数。

要解决此问题,请明确表示您希望User在第一个定义中接收结构:

  def subject_for_token(%User{id: id}, _claims) do
    {:ok, to_string(id)}
  end

  def subject_for_token(_, _) do
    {:error, :reason_for_error}
  end

也可以这样说resource_from_claims;这两个函数将匹配完全相同的参数。这也可以修复:

  def resource_from_claims(%{"sub" => sub}) do
    resource = Dailyploy.Accounts.get_user!(sub)
    {:ok, resource}
  end

  def resource_from_claims(_claims) do
    {:error, :reason_for_error}
  end
于 2019-07-12T10:01:22.720 回答
0

有人可以解释一下为什么这不起作用吗?

当您调用函数时,elixir 从定义中的第一个函数子句开始,并尝试将函数调用中指定的参数与函数定义中的参数相匹配。如果没有匹配,elixir 然后尝试下一个函数子句。当找到匹配项时,执行相应的函数体。如果没有任何函数子句匹配,那么您会收到 function_clause 错误。

让我们通过一个例子。如果你写:

def go({1, 2}, :cat) do
   IO.puts "I must have matched the function call."
end

那么您可以像这样调用该函数:

iex(2)> A.go({1, 2}, :cat)
I must have matched the function call.
:ok

但是,如果你尝试:

ex(3)> A.go("hello", 10)
** (FunctionClauseError) no function clause matching in A.go/2    

    The following arguments were given to A.go/2:

        # 1
        "hello"

        # 2
        10

    a.ex:2: A.go/2

您会收到函数子句错误,因为定义的函数子句没有go() 匹配函数调用:

  function call:     A.go("hello", 10)
                            |       |
            {1,2} = "hello  |       | :cat = 10
                            V       V
  function def:    def go({1, 2}, :cat) do

函数调用中唯一go()能匹配{1, 2}函数定义中元组{1, 2}的参数是元组,函数调用中唯一能匹配:cat函数定义中原子的参数是原子:cat

但是,函数定义中的变量匹配任何东西。合法变量名称的一些示例是:xy和。所以,如果你这样定义:_x_go()

  def go(_x, _y) do
    IO.puts "I must have matched the function call."
  end

那么两个函数调用将匹配:

iex(3)> c "a.ex"          
warning: redefining module A (current version defined in memory)
  a.ex:1
[A]

iex(4)> A.go("hello", 10)
I must have matched the function call.
:ok

iex(5)> A.go({1, 2}, :cat)
I must have matched the function call.
:ok

如果在 go() 定义中添加第二个函数子句:

  def go(_x, _y) do
    IO.puts "I must have matched the function call."
  end
  def go(_, _) do
    IO.puts "I will never match"
  end

第一个函数子句仍将匹配任何两个参数,并且因为是这种情况,所以第二个函数子句将永远不会执行——所以编译器会给你一个警告,相当于:

什么?当第二个函数子句永远不会匹配因此永远不会执行时,您为什么要在第二个函数子句中乱写所有垃圾?!控制!

当您在函数定义中进行模式匹配时,事情会变得有些棘手,例如:

def go(%{a: val}=map, x) do

请参阅此处了解其工作原理。

于 2019-07-12T16:02:05.600 回答