動かざることバグの如し

近づきたいよ 君の理想に

Elixirでファイルの読み書きまとめ

環境

  • Elixir 1.x

基本的な読み書き

File.write/2 で書き込み、 File.read/1 で読み込みできる。

iex> File.write "sample.txt", "Hello"
:ok
iex> File.read "sample.txt"
{:ok, "Hello"}

読み込んだときに2要素のタプルを返してくるのがポイント

こういう感じで分岐できる

case File.read("sample.txt") do
  {:ok, content} ->
    IO.inspect content
  {:error, reason} ->
    IO.puts "error: #{reason}"
  end

追記したい

第三引数に append を渡す

iex> File.write "sample.txt", "Hello"           
:ok
iex> File.write "sample.txt", " World", [:append]
:ok
iex> File.read "sample.txt"                      

エラー時に例外を発生させたい

関数名の最後にビックリマークをつける

iex> File.read! "404.txt"   
** (File.Error) could not read file "404.txt": no such file or directory
    (elixir) lib/file.ex:310: File.read!/1

ElixirでFizzBuzz

condを使う場合

defmodule FizzBuzz do
  def upto(n) do
    cond do
      rem(n, 15) == 0 -> "FizzBuzz"
      rem(n, 3) == 0 -> "Fizz"
      rem(n, 5) == 0 -> "Buzz"
      true -> n
    end
  end
end

for n <- 1..100 do
  IO.puts FizzBuzz.upto(n)
end

パターンマッチを使う場合

defmodule FizzBuzz do
  def upto(n) when rem(n, 15) == 0, do: "FizzBuzz"
  def upto(n) when rem(n, 3) == 0, do: "Fizz"
  def upto(n) when rem(n, 5) == 0, do: "Buzz"
  def upto(n), do: n
end

for n <- 1..100 do
  IO.puts FizzBuzz.upto(n)
end

参考リンク

Elixirで関数呼び出し時にドットを付ける/付けないの違い

環境

  • Elixir 1.x

結論

  • 無名関数の場合はドット(.)が必要
  • 名前付き関数の場合は不要

違いについて

他の言語やったあとにElixirやってると以下のようなエラーをよく起こす。

iex(1)> add = fn a, b -> a + b end
#Function<12.99386804/2 in :erl_eval.expr/5>
iex(2)> add(1, 2) 
** (CompileError) iex:2: undefined function add/2

実際には以下が正しい。

iex(2)> add.(1, 2)                
3

つまり関数呼び出し時にドットが抜けてたのだが、ドットを付けない場合もある。どういう違いがあるのか気になった。

利害は結構単純で、fnからendのキーワードを使って定義された関数は無名関数と呼ばれ、名前の通り関数名がない。

一方、defからendのキーワードで定義された関数は普通?の関数、名前付き関数になり、名前付き関数を呼び出す場合はドットを付けない。

defmodule Mymodule do
  def add(a, b) do
    a + b
  end
end

IO.puts Mymodule.add(1, 2)

逆にドットを付けて実行するとエラーになる。気をつけよう

Mymodule.add.(1, 2)

** (UndefinedFunctionError) function Mymodule.add/0 is undefined or private. Did you mean one of:

      * add/2

    Mymodule.add()
    hoge.exs:28: (file)
    (elixir) lib/code.ex:677: Code.require_file/2

PHPで文字列を1文字ずつ分割する方法が進化してた

令和最新版のPHPは一味違うぜ

概要

すごく昔に、PHPで文字列を1文字ずつの配列に変換する方法について記事を書いた。

thr3a.hatenablog.com

このときはメモ程度だったが、実は今でもそこそこPVがある。

流石に令和だしPHP7どころか8も出たしなにかアップデートあるやろ〜と冗談でドキュメント見てたら本当に進化してた。

環境

  • PHP 7.4以上

コード

ついにマルチバイト対応の関数mb_str_split()が実装された。以下のようにかける。

<?php
$str = "abcdeあい う えお";
$result = mb_str_split($str);
var_dump($result);

結果

array(12) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(1) "d"
  [4]=>
  string(1) "e"
  [5]=>
  string(3) "あ"
  [6]=>
  string(3) "い"
  [7]=>
  string(1) " "
  [8]=>
  string(3) "う"
  [9]=>
  string(3) " "
  [10]=>
  string(3) "え"
  [11]=>
  string(3) "お"

すげーーーーーーーー

PHP 8.0では

当然動く。が、8.0から失敗時の挙動が変わっているので注意。

この関数は、失敗時に false を返さなくなりました。