Phoenix 似乎在按字母顺序和模式匹配对参数进行重新排序——这正常吗?
Phoenix seems to be re-ordering params alphabetically and pattern matching - is this normal?
这是发送请求的前端代码——注意参数的顺序:
params = {ticket_guid: "XXX-XXX", user_name: "David", quantity: 2}
$.get('/init_stripe_transaction', params, function(data) {
这是浏览器开发控制台中显示参数顺序的 "Bad Request" 数据:
http://localhost:4000/init_stripe_transaction?ticket_guid=XXX-XXX&user_name=David&quantity=2
这是终端(服务器端)的错误响应,即 phoenix elixir def 日志。注意 - 由于某些原因,参数的顺序现在如何更改:
[info] GET /init_stripe_transaction
[debug] Processing with DiceWeb.TransactionController.create_stripe_session/2
Parameters: %{"quantity" => "2", "ticket_guid" => "XXX-XXX", "user_name" => "David"}
Pipelines: [:browser]
[info] Sent 400 in 357ms
[debug] ** (Phoenix.ActionClauseError) no function clause matching in DiceWeb.TransactionController.create_stripe_session/2
这就是我在控制器中进行模式匹配的方式:
def create_stripe_session(
conn,
%{ticket_guid: ticket_guid, user_name: user_name, quantity: quantity}
) do ...
额外供参考:我对 elixir/pattern 匹配非常陌生。所以决定堆栈溢出比在 phoenix repo 上制造问题要好。这样模式匹配可以吗?
啊哇 - 显然还在思考 Ruby。
- 顺序无关紧要。
:
!= =>
像这样使用地图进行模式匹配时。简单地用粗箭头样式替换符号样式就解决了我的问题。无论参数的顺序如何 - 更有意义。
1) 就像在ruby中一样,地图:
%{a: 1, b: 2}
是地图的简称:
%{:a => 1, :b => 2}
在 iex 中:
iex(1)> %{a: 1, b: 2} == %{:a => 1, :b => 2}
true
2) 在 Elixir 中,atom 不会被垃圾回收,因此 atom table 的大小有一个硬性限制,这是存储 atom 的地方. Phoenix 保护您免受有人发送 1 亿 name/value 对的请求,如果将这些请求作为 atom/value 对移交给您的应用程序,则会淹没原子 table。相反,您的控制器中的操作会收到带有 string/value 对的地图,然后您可以对其进行模式匹配以挑选出您感兴趣的 string/value 对。其余的 string/value 对将是垃圾集。按照惯例,然后将模式匹配的 key/value 对转换为 atom/value 对供内部使用,例如:
def world(conn, %{"name" => name}) do
render(conn, "world.html", name: name)
end
3) 字符串不等同于原子:
iex(1)> "a" == :a
false
因此,如果一个函数的参数变量指定了一个带有键原子的映射,该函数将不会与键为字符串的映射进行模式匹配:
defmodule My do
def go(%{:a => x}) do
IO.puts x
end
end
My.go(%{"a" => 10})
在命令行:
~/elixir_programs$ elixir a.exs
** (FunctionClauseError) no function clause matching in My.go/1
The following arguments were given to My.go/1:
# 1
%{"a" => 10}
a.exs:2: My.go/1
(elixir) lib/code.ex:767: Code.require_file/2
4) 最终,你会 运行 遇到这样的事情:
def go(%User{}) do
...
end
%User{}
匹配任何用户结构。
这是发送请求的前端代码——注意参数的顺序:
params = {ticket_guid: "XXX-XXX", user_name: "David", quantity: 2}
$.get('/init_stripe_transaction', params, function(data) {
这是浏览器开发控制台中显示参数顺序的 "Bad Request" 数据:
http://localhost:4000/init_stripe_transaction?ticket_guid=XXX-XXX&user_name=David&quantity=2
这是终端(服务器端)的错误响应,即 phoenix elixir def 日志。注意 - 由于某些原因,参数的顺序现在如何更改:
[info] GET /init_stripe_transaction
[debug] Processing with DiceWeb.TransactionController.create_stripe_session/2
Parameters: %{"quantity" => "2", "ticket_guid" => "XXX-XXX", "user_name" => "David"}
Pipelines: [:browser]
[info] Sent 400 in 357ms
[debug] ** (Phoenix.ActionClauseError) no function clause matching in DiceWeb.TransactionController.create_stripe_session/2
这就是我在控制器中进行模式匹配的方式:
def create_stripe_session(
conn,
%{ticket_guid: ticket_guid, user_name: user_name, quantity: quantity}
) do ...
额外供参考:我对 elixir/pattern 匹配非常陌生。所以决定堆栈溢出比在 phoenix repo 上制造问题要好。这样模式匹配可以吗?
啊哇 - 显然还在思考 Ruby。
- 顺序无关紧要。
:
!==>
像这样使用地图进行模式匹配时。简单地用粗箭头样式替换符号样式就解决了我的问题。无论参数的顺序如何 - 更有意义。
1) 就像在ruby中一样,地图:
%{a: 1, b: 2}
是地图的简称:
%{:a => 1, :b => 2}
在 iex 中:
iex(1)> %{a: 1, b: 2} == %{:a => 1, :b => 2}
true
2) 在 Elixir 中,atom 不会被垃圾回收,因此 atom table 的大小有一个硬性限制,这是存储 atom 的地方. Phoenix 保护您免受有人发送 1 亿 name/value 对的请求,如果将这些请求作为 atom/value 对移交给您的应用程序,则会淹没原子 table。相反,您的控制器中的操作会收到带有 string/value 对的地图,然后您可以对其进行模式匹配以挑选出您感兴趣的 string/value 对。其余的 string/value 对将是垃圾集。按照惯例,然后将模式匹配的 key/value 对转换为 atom/value 对供内部使用,例如:
def world(conn, %{"name" => name}) do
render(conn, "world.html", name: name)
end
3) 字符串不等同于原子:
iex(1)> "a" == :a
false
因此,如果一个函数的参数变量指定了一个带有键原子的映射,该函数将不会与键为字符串的映射进行模式匹配:
defmodule My do
def go(%{:a => x}) do
IO.puts x
end
end
My.go(%{"a" => 10})
在命令行:
~/elixir_programs$ elixir a.exs
** (FunctionClauseError) no function clause matching in My.go/1
The following arguments were given to My.go/1:
# 1
%{"a" => 10}
a.exs:2: My.go/1
(elixir) lib/code.ex:767: Code.require_file/2
4) 最终,你会 运行 遇到这样的事情:
def go(%User{}) do
...
end
%User{}
匹配任何用户结构。