Raku で文字列を反転させる時に多分考えること
"Twitter"
という文字列を反転させたいからと .reverse
メソッドを呼ぶと:
say "Twitter".reverse;
以下のようにかっこで囲まれた何かが返ってくる。
(Twitter)
これは .reverse
メソッドが配列用のメソッドであり、スカラーに対して呼び出すと要素が 1 つの配列として認識されてしまい、
配列が返ってくるからだ。
.^name
を呼ぶと戻り値の型の名前を表示することができる。
say "Twitter".reverse.^name;
すると、Seq
と表示された。
Seq
1 文字ずつに分割して(.split("")
)、結合すれば(.join
)、
Twitter".split("").reverse.join;
目的の値を得ることができる:
rettiwT
のだが、幸い Str
クラスには .flip
というそのズバリのメソッドがある。
say "Twitter".lc.flip.tc;
Rettiwt
他人が書いたコードを読んでいる時に 10 億回くらい思うこと
他人が書いたコードを読んでいる時に 10 億回くらい思うことを書いておこうと思う。
using
してるのに finally
で Dispose()
したり Close()
しちゃう
何もわからないのだが、よく using
で囲っているのにその中の try
... finally
文の finally
節で Dispose()
したり Close()
してしまっているコードを見る。
以下はとても典型的なコードで、もう一つ問題があるのだが、これは次で解説する。
dim result = new DataTable() using reader = command.ExecuteReader() try result.Load( reader ) finally reader.Dispose() end try end using return result
ここで、reader
は明らかに IDisposable
を実装しているのですごく単純に考えると end using
のところで自動的に Dispose()
されるので、finally
の reader.Dispose()
は必要ない。
多分、このコードを書くような人は、古 Java 話者の人か古 Java を少し話せる人で、using
をただのおまじないか何かと思っているのだろう。
私が書き直すなら以下のようになる:
dim result = new DataTable() using reader = command.ExecuteReader() try result.Load( reader ) catch ex as Exception Trace.TraceError( ex.ToString() ) end try end using return result
finally
の替わりに catch
節にして、例外を出力ウィンドウに出力するようにした。
スコープ引き伸ばし症
先程書き直したコードだが、まだ改善するべき箇所がある。
それは result
の宣言を using
スコープの外に出している点である。
dim result = new DataTable() using reader = command.ExecuteReader() try result.Load( reader ) catch ex as Exception Trace.TraceError( ex.ToString() ) end try end using return result
スコープの範囲を最小限にする原則からすれば、result
の宣言は try
節の中で良いし、result
を return
するところも try
節の中でいい。
そのことを踏まえて書き直すと以下のようになる:
using reader = command.ExecuteReader() try dim result = new DataTable() result.Load( reader ) return result catch ex as Exception Trace.TraceError( ex.ToString() ) end try end using
vim で置換する方法
:%s/buster/bullseye/g
WSL2 の Debian を 10(buster) から 11(bullseye) にアップグレードした
/etc/apt/sources.list
の buster
を bullseye
に変更する。
deb http://deb.debian.org/debian buster main deb http://deb.debian.org/debian buster-updates main deb http://security.debian.org/debian-security/ buster/updates main deb http://ftp.debian.org/debian buster-backports main
これが
deb http://deb.debian.org/debian bullseye main deb http://deb.debian.org/debian bullseye-updates main deb http://security.debian.org/debian-security/ bullseye/updates main deb http://ftp.debian.org/debian bullseye-backports main
こうなる。
3 行目が無いらしく、ここをコメントアウトした。
次に
% sudo apt update
する。 ここで何かしらエラーが出たりする。
この後、
% sudo apt upgrade
を行うとパッケージを更新してくれる。 その後に
% sudo apt full-upgrade
とやると完全にアップグレードできるらしい。
うまくいった。
VB で 1 行ラムダ式を書きたい時
定義するとき:
dim succ = function(x) x + 1
使うとき:
Console.WriteLine( succ( 23 ) )
こういうような匿名型の配列を Dictionary
にするには:
dim products = { new with { .Name = "オレンジ", .Price = 100 }, new with { .Name = "リンゴ" , .Price = 120 } }
こういう風に書ける:
dim productMap = products.ToDictionary( function(product) product.Name, function(product) product.Price )
参考
VB 書いてるときに任意の型の Type 型を取得するいくつかの方法
VB に触れるのは久しぶりなので、右と左はおろか箸を持つ方の手がどっちなのか全然わからない。
C# においてこういう風に書いていたコードも:
aTable.Columns.Add( new DataColumn { DataType = typeof(string), ColumnName = "Name" } );
VB ではどう書けばいいのかわからない(with
を使うらしい…)。
C# における typeof(string)
は VB においては GetType(String)
らしい。
先程の例は以下のように書ける:
aTable.Columns.Add( new DataColumn with { .DataType = GetType(String), .ColumnName = "Name" } )
いくつかの方法なのに、1 つしか書いてないけどまあいいか。
参照
VB の char 型リテラル
Msys2 で Guile をビルドする時にビルドする人がしなければいけないこと
ビルドする際、以下のようなコンパイルエラーが出る::
net_db.c: In function 'scm_gethost':
net_db.c:144:18: error: storage size of 'inad' isn't known
144 | struct in_addr inad;
| ^~~~
net_db.c:174:21: warning: implicit declaration of function 'htonl' [-Wimplicit-function-declaration]
174 | inad.s_addr = htonl (scm_to_ulong (host));
| ^~~~~
net_db.c:185:15: error: invalid application of 'sizeof' to incomplete type 'struct in_addr'
185 | if (sizeof (struct in_addr) != entry->h_length)
| ^~~~~~
net_db.c:193:14: error: dereferencing pointer to incomplete type 'struct in_addr'
193 | inad = *(struct in_addr *) argv[i];
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
net_db.c:194:39: warning: implicit declaration of function 'ntohl' [-Wimplicit-function-declaration]
194 | lst = scm_cons (scm_from_ulong (ntohl (inad.s_addr)), lst);
| ^~~~~
net_db.c:144:18: warning: unused variable 'inad' [-Wunused-variable]
144 | struct in_addr inad;
| ^~~~
In file included from net_db.c:60:
net_db.c: In function 'scm_return_entry':
net_db.c:325:53: warning: implicit declaration of function 'ntohs' [-Wimplicit-function-declaration]
325 | SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_uint16 (ntohs (entry->s_port)));
| ^~~~~
vectors.h:72:73: note: in definition of macro 'SCM_SIMPLE_VECTOR_SET'
72 | #define SCM_SIMPLE_VECTOR_SET(x,idx,val) ((SCM_I_VECTOR_WELTS(x))[idx]=(val))
| ^~~
net_db.c: In function 'scm_getserv':
net_db.c:374:30: warning: implicit declaration of function 'htons' [-Wimplicit-function-declaration]
374 | entry = getservbyport (htons (scm_to_int (name)), protoname);
| ^~~~~
make[3]: *** [Makefile:3446: libguile_3.0_la-net_db.lo] Error 1
なぜかというと、よくわからないんだけど guile
では、中に標準?ヘッダーファイルを生成してそれを使っているため、
msys2 では netinet/in.h
でインクルードされている cygwin/in.h
がインクルードされていないという問題が起こる。
なので、 $(top_srcdir)/lib/netinet/in.h
に以下のように書いておく必要がある::
#ifdef __CYGWIN__ #include <cygwin/in.h> #endif
こうすると、すんなりビルドできる。
それで、この $(top_srcdir)/lib/netinet/in.h
は、 ./configure
を実行すると、元に戻る気がするので注意。
空気ねこにもおおよそ分かるにんげんは牛ではないことを RSpec で証明してみた
ネットミームをコードで表現してみるかもしれないシリーズ。
まあ、にんげん(Human
)と牛(Cow
)の抽象クラス Animal
を定義する:
# lib/animal.rb class Animal end
中身は何も無いけど、そのうち実装されるっしょ。ヘーキヘーキ。
ここら辺で Animal
クラス必要ないなって思ったけど、まあいいか。
ああ、次は牛とにんげんだ…。
# lib/cow.rb require_relative 'animal' class Cow < Animal end
次はにんげん。
# lib/human.rb require_relative 'animal' class Human < Animal end
何も中身ないけど、ヘーキヘーキ。
ということで、スペックファイルを書いてみよう。
describe Human do it 'にんげんは牛ではない' do # TODO: ここでにんげんは牛ではないことをしょーめーする end end
ここで describe
のブロックの中で Human
は described_class
って書けるらしい。
さて、にんげんは牛ではないことを調べるにはどうすればいいだろう?
とぼけるのも疲れてきたので、長年温めてきた常識を働かせてみると、明らかに Human
と Cow
は別のものだ。
つまり:
if Human != Cow then puts 'にんげんは牛じゃないよ!' else puts 'ふえぇぇ………、にんげんは牛だったようです………' end
ってやって、「にんげんは牛じゃないよ!」って表示されればいいわけだ。そうだよね?
こーいうのを RSpec でかっこよく書きたい。
RSpec ではテストする主体?を except()
に渡す。それで、 .to
ってやって……
同じかどうか調べるには equal()
に調べたい値を渡す。
except( described_class ).to equal( Cow )
いいぞ!
described_class
の替わりに Human
って書いても良い。
except( Human ).to equal( Cow )
いいね!
でもちょっと待って。
こうすると、Human
と Cow
は同じかどうか調べることになってしまう!
どうしよう?!
.to
の替わりに .to_not
を使うことで、式の否定版にすることができる。
じゃあ、こんな感じかな?
except( described_class ).to_not equal( Cow )
うまくいった!
it
の中に移してみよう:
describe Human do it 'にんげんは牛ではない' do except( described_class ).to_not equal( Cow ) end end
おしまい。
完成したのが こっちにあるので、てきとーに答え合わせしてみてね。