LoginSignup
0

この記事は Elixir その2 Advent Calendar 2020 14日目です。

先日は@torifukukaiou さんの「GigalixirでPORTを4000以外の値にするのはだめよ (Elixir)」でした。
@torifukukaiou さん13日間お疲れさまでした。しばらく休憩してください。

Elixir楽しいです。少しでも多くの方とその楽しみを共有したいものです。日頃、色んな人のメモにお世話になっているので、僕も勉強した内容をどんどんアウトプットしていこうと思います。

はじめに

Elixirではシングルクオート('Hello')とダブルクオート("Hello")が同義ではないと何となく分かっていながら、シングルクオートを使う機会が今まで全くありませんでした。使わないので結局、よくわからないまま放置してありました。

が、NervesでIoTのシリアル通信の勉強をしていて戸惑うことがあったので、学んだ内容を軽くメモをしました。

因みにNervesでのIoT開発/電子工作はかなり楽しいので興味のある方には#NervesJP Advent Calendar 2020をおすすめします。

戸惑ったこと

シリアル通信でStringの文字一つ一つをバイトとして送信する際に、StringからCharlistへの変換が必要であること。それを理解してなかった。

# データ送信関数イメージ
iex> send_byte = fn x -> IO.puts("#{x}を送信") end

# 失敗イメージ
iex> "Hello" |> Enum.each(send_byte)
** (Protocol.UndefinedError) protocol Enumerable not implemented for "Hello" of type BitString. This protocol is implemented for the following type(s): RingLogger.CircularBuffer, HashSet, Range, Map, Function, List, Stream, Date.Range, HashDict, GenEvent.Stream, MapSet, File.Stream, IO.Stream
    (elixir 1.11.2) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir 1.11.2) lib/enum.ex:141: Enumerable.reduce/3
    (elixir 1.11.2) lib/enum.ex:3461: Enum.each/2

# 成功イメージ
iex> 'Hello' |> Enum.each(send_byte)
72を送信
101を送信
108を送信
108を送信
111を送信
:ok

""''の違いを確認

マッチ演算子=

"Hello" = 'Hello'
** (MatchError) no match of right hand side value: 'Hello'

比較演算子==

"Hello" == 'Hello'
false

IO.inspect

iex> IO.inspect("Hello")
"Hello"

iex> IO.inspect('Hello')
'Hello'

なんの情報も得られませんでした。

iexのi ヘルパー関数

iex> i "Hello"

Term
  "Hello"
Data type
  BitString
Byte size
  5
Description
  This is a string: a UTF-8 encoded binary. It's printed surrounded by
  "double quotes" because all UTF-8 encoded code points in it are printable.
Raw representation
  <<72, 101, 108, 108, 111>>
Reference modules
  String, :binary
Implemented protocols
  Collectable, IEx.Info, Inspect, List.Chars, String.Chars
iex> i 'Hello'

Term
  'Hello'
Data type
  List
Description
  This is a list of integers that is printed as a sequence of characters
  delimited by single quotes because all the integers in it represent printable
  ASCII characters. Conventionally, a list of Unicode code points is known as a
  charlist and a list of ASCII characters is a subset of it.
Raw representation
  [72, 101, 108, 108, 111]
Reference modules
  List
Implemented protocols
  Collectable, Enumerable, IEx.Info, Inspect, List.Chars, String.Chars

具体的な違いが見えてきました。

# a string: a UTF-8 encoded binary
"Hello" = <<72, 101, 108, 108, 111>>

# a list of integers
'Hello' = [72, 101, 108, 108, 111]

データタイプが全く違うんですね。

is_binary("Hello") #=> true
is_binary('Hello') #=> false

is_bitstring("Hello") #=> true
is_bitstring('Hello') #=> false

is_list("Hello") #=> false
is_list('Hello') #=> true

"Hello"'Hello'に変換

Kernel.to_charlistで可能。

"Hello" |> to_charlist                    #=> 'Hello'
<<72, 101, 108, 108, 111>> |> to_charlist #=> 'Hello'

'Hello'"Hello"に変換

Kernel.to_stringで可能。

'Hello' |> to_string                  #=> "Hello"
[72, 101, 108, 108, 111] |> to_string #=> "Hello"

IO.inspectのオプションを変えてみる

iex> IO.inspect("Hello", binaries: :as_binaries)
<<72, 101, 108, 108, 111>>
"Hello"

iex> IO.inspect('Hello', charlists: :as_lists)
[72, 101, 108, 108, 111]
'Hello'

もう一回正しい理解でデータ送信

iex> send_byte = fn x -> IO.puts("#{x}を送信") end
#Function<44.97283095/1 in :erl_eval.expr/5>

iex> "Hello" |> to_charlist |> Enum.each(send_byte)
72を送信
101を送信
108を送信
108を送信
111を送信
:ok

さいごに

因みにやりたかったことはLCDに書き込むときのこういうやつです。

ここまでまとめてみて、やっと基本が分かってきました。更にElixir - Getting Startedの例のようなUnicodeに対応する場合は文字によっては隠れたバイトがあるので、もう少しややこしい場合があるようです。

Elixir その2 Advent Calendar 2020 初日[87, 101, 32, 97, 114, 101, 32, 116, 104, 101, 32, 65, 108, 99, 104, 101, 109, 105, 115, 116, 115, 44, 32, 109, 121, 32, 102, 114, 105, 101, 110, 100, 115, 33]
に改めて戻ってみると、おもしろいです。

明日は「[Elixir] GenServerのCallとCast」です。引き続き、Elixirを楽しみましょう。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0