gpt4 book ai didi

binary - 逗号分隔的二进制参数? - Elixir

转载 作者:行者123 更新时间:2023-12-01 01:41:01 25 4
gpt4 key购买 nike

这个月我一直在学习 elixir,当时我想将二进制对象转换为位列表,以进行模式匹配。

我的研究引领我 here , 到显示这样做的方法的文章。但是,我并不完全理解传递给 extract 的参数之一。功能。

我可以复制并粘贴代码,但我想了解这里的幕后情况。

论点是这样的:<<b :: size(1), bits :: bitstring>> .

我的理解

我明白 << x >>表示一个二进制对象 x .从逻辑上讲,我认为这类似于执行:[head | tail] = list在 List 上,获取第一个元素,然后将剩余的元素作为一个名为 tail 的新列表。

我不明白的地方

不过语法我不熟悉,也没见过::在 elixir 中,我也从未见过用逗号分隔的二进制对象:, .我也是,没看过size(x)在 Elixir 中使用,从未遇到过 bitstring .

底线

如果有人可以准确解释此参数的语法是如何分解的,或者将我指向一个资源,我将不胜感激。

为方便起见,该文章中的代码:

defmodule Bits do
# this is the public api which allows you to pass any binary representation
def extract(str) when is_binary(str) do
extract(str, [])
end

# this function does the heavy lifting by matching the input binary to
# a single bit and sends the rest of the bits recursively back to itself
defp extract(<<b :: size(1), bits :: bitstring>>, acc) when is_bitstring(bits) do
extract(bits, [b | acc])
end

# this is the terminal condition when we don't have anything more to extract
defp extract(<<>>, acc), do: acc |> Enum.reverse
end

IO.inspect Bits.extract("!!") # => [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1]
IO.inspect Bits.extract(<< 99 >>) #=> [0, 1, 1, 0, 0, 0, 1, 1]

最佳答案

Elixir pattern matching seems mind blowingly easy to use for structured binary data.



是的。你可以感谢 erlang 的发明者。

According to the documentation, <<x :: size(y)>> denotes a bitstring, whos decimal value is x and is represented by a string of bits that is y in length.



让我们稍微简化一下: <<x :: size(y)>>是插入到 y 位的整数 x。例子:
<<1 :: size(1)>>  => 1
<<1 :: size(2)>> => 01
<<1 :: size(3)>> => 001
<<2 :: size(3)>> => 010
<<2 :: size(4)>> => 0010
binary中的位数类型可被 8 整除,因此二进制类型具有整数字节(1 字节 = 8 位)。 bitstring 中的位数不能被 8 整除。这就是 binary 之间的区别类型和 bitstring类型。

I understand that << x >> denotes a binary object x. Logically to me, it looks as though this is similar to performing: [head | tail] = list on a List, to get the first element, and then the remaining ones as a new list called tail.



是的:
defmodule A do

def show_list([]), do: :ok
def show_list([head|tail]) do
IO.puts head
show_list(tail)
end

def show_binary(<<>>), do: :ok
def show_binary(<<char::binary-size(1), rest::binary>>) do
IO.puts char
show_binary(rest)
end

end

在 iex 中:
iex(6)> A.show_list(["a", "b", "c"])    
a
b
c
:ok

iex(7)> "abc" = <<"abc">> = <<"a", "b", "c">> = <<97, 98, 99>>
"abc"

iex(9)> A.show_binary(<<97, 98, 99>>)
a
b
c
:ok

或者您可以将二进制中的整数解释为普通的旧整数:
  def show(<<>>), do: :ok

def show(<<ascii_code::integer-size(8), rest::binary>>) do
IO.puts ascii_code
show(rest)
end

在 iex 中:
iex(6)> A.show(<<97, 98, 99>>)            
97
98
99
:ok
utf8 type 非常有用,因为它会根据需要抓取尽可能多的字节来获取整个 utf8 字符:
  def show(<<>>), do: :ok

def show(<<char::utf8, rest::binary>>) do
IO.puts char
show(rest)
end

在 iex 中:
iex(8)> A.show("ۑ")
8364
235
:ok

如您所见, uft8 type 返回字符的 unicode 代码点。将字符作为字符串/二进制获取:
  def show(<<>>), do: :ok
def show(<<codepoint::utf8, rest::binary>>) do
IO.puts <<codepoint::utf8>>
show(rest)
end

您获取代码点(一个整数)并使用它来创建二进制/字符串 <<codepoint::utf8>> .

在 iex 中:
iex(1)> A.show("ۑ")

ë
:ok

您不能为 utf8 指定大小但是,如果要读取多个 utf8 字符,则必须指定多个段。

当然还有段 rest::binary ,即 binary没有指定大小的类型,非常有用。它只能出现在模式的末尾,并且 rest::binary就像贪婪的正则表达式: (.*) . rest::bitstring 也是如此.

尽管 elixir 文档没有在任何地方提及它,但 total number of bits在一个段中,其中一个段是其中之一:
     |              |          |    
v v v
<< 1::size(8), 1::size(16), 1::size(1) >>

实际上是 unit * size ,其中每种类型都有一个默认值 unit .段的默认类型是 integer ,所以上面每个段的类型默认为 integer .整数有一个默认值 unit 1 位,所以第一段的总位数为: 8 * 1 bit = 8 bits .默认 unitbinary类型是 8 位,所以一个段像:
<< char::binary-size(6)>>

总大小为 6 * 8 bits = 48 bits .等效地, size(6)只是字节数。您可以指定 unit就像你可以 size ,例如 <<1::integer-size(2)-unit(3)>> .该段的总位大小为: 2 * 3 bits = 6 bits .

However, I'm not familiar with the syntax



看一下这个:
  def bitstr2bits(bitstr) do
for <<bit::integer-size(1) <- bitstr>>, do: bit
end

在 iex 中:
iex(17)> A.bitstr2bits <<1::integer-size(2), 2::integer-size(2)>>   
[0, 1, 1, 0]

等效地:
iex(3)> A.bitstr2bits(<<0b01::integer-size(2), 0b10::integer-size(2)>>)
[0, 1, 1, 0]

Elixir 倾向于使用库函数抽象出递归,因此通常您不必像在链接中那样提出自己的递归定义。但是,该链接显示了标准的基本递归技巧之一:向函数调用添加累加器以收集您希望函数返回的结果。该函数也可以这样写:
  def bitstr2bits(<<>>), do: [] 
def bitstr2bits(<<bit::integer-size(1), rest::bitstring>>) do
[bit | bitstr2bits(rest)]
end

链接处的累加器函数是尾递归的,这意味着它占用恒定(少量)内存——无论需要多少递归函数调用来遍历位串。一个有 1000 万位的位串?需要 1000 万次递归函数调用?那只需要少量的内存。在过去,我发布的替代定义可能会使您的程序崩溃,因为它会为每个递归函数调用占用越来越多的内存,并且如果位串足够长,则所需的内存量将太大,您将得到 stackoverflow,你的程序就会崩溃。但是,erlang 优化了递归函数不是尾递归的缺点。

关于binary - 逗号分隔的二进制参数? - Elixir ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57151352/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com