【问题标题】:String.replace raises RuntimeError in Enum.reduceString.replace 在 Enum.reduce 中引发 RuntimeError
【发布时间】:2017-04-17 15:30:58
【问题描述】:

我正在尝试在此 Elixir 代码中调用 String.replace,该代码从 structs 列表中获取其值,但这只会导致运行时错误。

String.replace 函数的字符串参数都打印出来了,看起来一切正常。为什么会这样?


这是导致错误的行:

Enum.reduce(structList, sslCmd, fn(x, sslCmd) -> String.replace(sslCmd, "{{#{x.key}}}", x.value) end)
# Runtime error here


** (ArgumentError) argument error
    (stdlib) binary.erl:275: :binary.replace/4
    (elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/code.ex:363: Code.require_file/2

这是完整的代码:

defmodule ParamStruct do                                                                                                                         
  defstruct key: "", value: "", default: "", description: "description of parameter", label: "label on web form", required: false, order: 99     
end                                                                                                                                              

defmodule TemplateStruct do                                                                                                                      
  defstruct key: "must be unique", name: "descriptive name", code: "", executable: false, destination: "", delete_after: false,                  
  perms: "644"                                                                                                                                   
end                                                                                                                                              

defmodule ProcessList do                                                                                                                         
  def parse_list([]), do: []                                                                                                                     

  def parse_list([%{"key" => ky,"value" => val,"default" => dft, "description" => desc,"label" => lbl} | tail]) do
    [%ParamStruct{key: ky, value: val, description: desc, label: lbl, default: dft } | parse_list(tail) ]
  end                                                                                                                                            

  def create_recommend_list(%{"itemScores" => score_list})  do                                                                                   
    parse_list(score_list)                                                                                                                       
  end                                                                                                                                            
end   

params = [                                                                                                                                     
%{"key" => "ca_cert_subj_state","value" => "Greater London","default" => "Greater London","description" => "Region","label" => "State/County"},                
  %{"key" => "key-file","value" => "cacert_001","default" => "cacert_001","description" => "","label" => "Key File (without password)"},                   
  %{"key" => "key-file-pass","value" => "cacert_pass_001","default" => "cacert_pass_001","description" => "","label" => "Key File (with password)"},            
  %{"key" => "ca_cert_email","value" => "admin@domain.net","default" => "admin@domain.net","description" => "","label" => "Email"},                              
  %{"key" => "ca_cert_subj_common_name","value" => "Elixir User","default" => "domain.net","description" => "","label" => "Common Name"},                   
  %{"key" => "ca_cert_subj_country","value" => "UK","default" => "UK","description" => "Country","label" => "Country"},                            
  %{"key" => "ca_cert_subj_location","value" => "Manchester","default" => "Westchester","description" => "","label" => "Location"},                        
  %{"key" => "ca_cert_subj_organization","value" => "Elixir Programs Forum","default" => "Big Company","description" => "","label" => "Organisation"},                
  %{"key" => "ca_cert_subj_org_unit","value" => "IT Department","default" => "Infosystems and Communications","description" => "","label" => "Organisational Unit"}                                                                                                                                            
  ]          

sslCmd = '''
openssl req -x509 -new -nodes -sha256 \
 -key {{key-file-pass}}.key \
 -days 3650 \
 -out {{key-file-pass}}.pem \
 -subj "\
/C={{ca_cert_subj_country}}\
/ST={{ca_cert_subj_state}}\
/L={{ca_cert_subj_location}}\
/O={{ca_cert_subj_organization}}\
/OU={{ca_cert_subj_org_unit}}\
/CN={{ca_cert_subj_common_name}}\
/emailAddress={{ca_cert_email}}\

'''
structList = ProcessList.parse_list(params)  
#IO.inspect ProcessList.parse_list(params)
# [first | _ ] = ProcessList.parse_list(params)
# IO.puts " #{first.key} is #{first.value} "

# IO.inspect first
IO.puts sslCmd
IO.puts "list of keys and values"
IO.puts "======================="
Enum.reduce(structList, sslCmd, fn(x, sslCmd) -> IO.puts " #{x.key} is #{x.value} " end) 

Enum.reduce(structList, sslCmd, fn(x, sslCmd) -> String.replace(sslCmd, "{{#{x.key}}}", x.value) end)
# Runtime error here

** (ArgumentError) argument error
    (stdlib) binary.erl:275: :binary.replace/4
    (elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/code.ex:363: Code.require_file/2

【问题讨论】:

    标签: elixir


    【解决方案1】:

    你的问题是sslCmdChar List, not a String,这就是为什么你不能在它上面调用String.replace(它只适用于字符串,也就是二进制文件)。

    最简单的解决方案是将sslCmd的值改为:

    sslCmd = """
    openssl req -x509 -new -nodes -sha256 \
     -key {{key-file-pass}}.key \
     -days 3650 \
     -out {{key-file-pass}}.pem \
     -subj ""\
    /C={{ca_cert_subj_country}}\
    /ST={{ca_cert_subj_state}}\
    /L={{ca_cert_subj_location}}\
    /O={{ca_cert_subj_organization}}\
    /OU={{ca_cert_subj_org_unit}}\
    /CN={{ca_cert_subj_common_name}}\
    /emailAddress={{ca_cert_email}}\
    """
    

    (注意双引号 """ 而不是单引号 '''

    【讨论】:

    • 谢谢 - 其他人提到了它,但我认为它适用于 String.replace 的参数。 String.replace 的匿名函数应该更新 sslCmd 不起作用,我认为这是由于不变性。我该如何重组以及需要添加哪些变量来避免这种情况?
    猜你喜欢
    • 2017-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多