maps string question

Hugo Mills hugo@REDACTED
Wed Oct 13 23:23:16 CEST 2021


On Wed, Oct 13, 2021 at 11:05:33PM +0200, Java House wrote:
> Hello
> I am having a problem with maps and strings as keys.
> My understanding that the the two string formats "string" and <<"string">>
> are identical but as you can see from the transcript bellow maps does not
> think so.

   No, they're not identical.

   "foo" is a list of integers, one per code-point in the string.
<<"foo">> is a binary, which is a packed sequence of bytes.  There's a
third form for strings, the iolist, which is a (possibly deeply)
nested list of lists and/or binaries. This is what you often get back
from the functions in the string module, for example.

   The two (three) forms are not equal, even if representing the same
conceptual string, so "foo" and <<"foo">> will compare differently.

> I searched but I couldn't find any function to convert form "string" to
> <<"string">> or the other way around.

   erlang:list_to_binary/1 and erlang:binary_to_list/1,3 would do the
job if your strings are purely ASCII (i.e. code-points of 127 or
less). Otherwise, unicode:characters_to_binary/1,2,3 and
unicode:characters_to_list/1,2 are probably the place to look. The
unicode functions and the list_to_binary function will also accept
iolists.

> How can I make maps to accept both format of strings?

   They'll acccept both... but they'll look like different keys. You
can't make the list do an automatic conversion. You need to decide on
which of the two forms you're going to use (I recommend binaries), and
ensure that every access converts to binary before using a map
accessor. You may want to write some helper functions for this.

   Hugo.

> Erlang/OTP 24 [erts-12.0] [source] [64-bit] [smp:8:8] [ds:8:8:10]
> [async-threads:1] [jit]
> 
> Eshell V12.0  (abort with ^G)
> 1> Key1 = "key1".
> "key1"
> 2>
> 2> Key11 = <<"key1">>.
> <<"key1">>
> 3>
> 3> string:equal(Key1, Key11).
> true
> 4>
> 4> Map = maps:new().
> #{}
> 5>
> 5> Map1 = maps:put("key1", {something}, Map).
> #{"key1" => {something}}
> 6>
> 6> maps:get(Key1, Map1).
> {something}
> 7>
> 7> maps:get(Key11, Map1).
> ** exception error: bad key: <<"key1">>
>      in function  maps:get/2
>         called as maps:get(<<"key1">>,#{"key1" => {something}})
>         *** argument 2: not a map
> 8>
> 8> maps:get("key1", Map1).
> {something}
> 9>
> 9> maps:get(<<"key1">>, Map1).
> ** exception error: bad key: <<"key1">>
>      in function  maps:get/2
>         called as maps:get(<<"key1">>,#{"key1" => {something}})
>         *** argument 2: not a map
> 10>

-- 
Hugo Mills             | You can play with your friends' privates, but you
hugo@REDACTED carfax.org.uk | can't play with your friends' childrens' privates.
http://carfax.org.uk/  |
PGP: E2AB1DE4          |                                       C++ coding rule


More information about the erlang-questions mailing list