Java系エンジニアがRubyでつまづいたこと
&.
と書くoptional chaining的なものの挙動が変
後続処理の違い
TypeScriptやKotlinでは、?.
ですが、それと同じと思っていたら、違いました。
let a: { s: string } | null = {s: "hello world"}
a?.s.length // 11
a = null
a?.s.length // undefined
TypeScriptではこうですが、これと同じノリでRubyで書いたら…
require 'ostruct'
a = OpenStruct.new(s: "hello world")
a&.s.length # 11
a = nil
a&.s.length # undefined method `length' for nil:NilClass (NoMethodError)
エラーになりました…。
a&.s&.length # 11
Rubyではこう書かないといけないようです。
case class A(s: String)
var a: Option[A] = Some(A("hello world"))
// a.map(x => x.s.length)のシンタックスシュガーです
a.map(_.s.length) // Option[Int] = Some(11)
a = None
a.map(_.s.length) // Option[Int] = None
Scalaで同様のコードを書くとこうです。値があった場合のみ処理されるので、そのあたりがTypeScriptと使う脳が一緒ですね。
配列へのアクセスが変
arr = [1,2,3]
arr&.[2] # syntax error, unexpected '[' (SyntaxError)
arr&.[](2) # 3
RubyでOptional Chainingして、添字でアクセスする、となるとなった途端に書き方が変わる…。
const arr = [1,2,3]
arr?.[2]
TypeScriptでは、添字でアクセスする場合でも変わらない。
:コロンが前なのか後ろなのかルールが覚えられない
irb(main):001:0> {"key": 1}
=> {:key=>1}
irb(main):002:0> {key: 1}
=> {:key=>1}
irb(main):003:0> {:key => 1}
=> {:key=>1}
irb(main):004:0> {"key" => 1}
=> {"key"=>1}
irb(main):005:0> {:"key" => 1}
=> {:key=>1}
ハッシュはこうだし
メソッドの引数も
def method1(aaa:)
となるし…
これはなかなか覚えられませんでした
injectとも書けて、reduceともかける
脳に定着せず、学習コストが上がるような…
raise~rescue,とthrow~catchの違い
raise~rescue,とthrow~catchの違い、本当にわかってる?まとめた - Qiita
Javaの文脈でthrowと言ったら、誤解されましたので、Rubyでの開発をする場合は、throwとraiseの違いを意識しましょう。
aliasは、alias_methodの違いなど
# カンマが要らない。カンマつけるとエラーになる。メソッドではなく、キーワードらしい。
alias rename_method1 method1
# シンボルにしてもいいみたい
alias :rename_method1 :method1
# alias :rename_method1, :method1 # error
# alias_methodというメソッドのためカンマをつける必要がある。メソッドへの引数なので、:をつけてシンボルにする必要がある。
# IntelliJは、メソッドの場合は、明るいほうのオレンジにしてくれるみたい。
alias_method :rename_method2, :method2
# alias_method rename_method2, method2 # error
# alias_method :rename_method2 :method2 # error
# Ruby標準のグローバルなメソッドじゃないものはオレンジ色にならないっぽい?
attr_reader2 :variable1, :variable2, :variable3
IntelliJでの見え方
lambdaとprocとblockの違いが難しい
Rubyの ブロック、Proc.new、lambdaの違い - Qiita
static privateメソッドを書くのにクセがある
Rubyでprivateなクラスメソッドを定義するには - ESM アジャイル事業部 開発者ブログ
正しくrequireできているかを知る術が無い
IDEでオートインポートされない(される設定があるなら教えてほしい)ので、自分で書く必要がある。
Zeitwerkなどを使っていて、requireを書く必要を無くす、というのが解決策なんでしょうね…きっと。
ラムダの記法が独特
->(e) { }
ラムダの->なぜそこにつけた。
===という記号は左右対称なのに、実行結果が「左右対称」じゃない
Rubyの===演算子についてまとめてみた|TechRacho by BPS株式会社
mapのなかでreturnを書いてしまうと意図しない挙動になる
このあたりがメソッドとブロックの違いのようです。
解決法は、以下に記載がある
リファクタリングと妥協を繰り返して君だけの.rubocop.ymlを作ろう - ARMERIA
ブロック内のnextは、次の処理へ進むという意味と思いきや、そうでもないときがある
def block_example
yield
puts "after block"
end
block_example do
puts "hello world"
next
puts "not executed"
end
例として、こういったものです。
実行結果は、
hello world
after block
となります。
nextとはいったい…。
unless使いこなせない
if !(hogehoge)
じゃダメなのかな…。いつも見慣れたコードと違うコードになってしまい、読むのに時間がかかってしまいます。
インデント
privateがインデントの階層が同じレベルにあるので分かりづらい。
moduleで階層が深くなってしまう。
numerable#each_with_objectとEnumerable#reduceの引数の位置が違う
ブロックをオブジェクトとして、渡したり取得する場合、&で渡す
def call_block(&block)
block.call
end
call_block { puts "Hello, block!" }
C++の参照渡しのように見えるが、そうではない。
@1個でも使い方次第で、クラスインスタンス変数とインスタンス変数が変わる
class A
@value = 1
def self.static_value
@value
end
def self.static_set_value(v)
@value = v
end
def value
@value
end
def set_value(v)
@value = v
end
end
a0 = A.new
A.static_set_value(5)
a0.set_value(6)
puts "A.static_value"
puts A.static_value # 5
puts "a0.value"
puts a0.value # 6
staticメソッドかそうじゃないかでインスタンス変数かクラスインスタンス変数かが変わる…
引数に&blockと書いていない場合でも、ブロックを引数に取れる
def my_method
yield("hello", 1)
yield("world", 2)
end
my_method do |message, number|
puts "#{message}, #{number}"
end
引数に&blockと書いていないから、メソッドシグネチャが分かりづらい。
blockを受け取って処理できるということが実装を見ないと分からない。
Rubyのprivateメソッド、protectedメソッドの挙動がJavaとは違う
JavaやC#の常識が通用しないRubyのprivateメソッド - give IT a try
doをつけるのかつけないのかよくわからない
class A do
def method1 do
puts("hello world")
end
end
と書いてしまう…
ヒアドキュメントの記号が3つもある
<<
<<-
<<~
の3種類もある…
if式があるのに、3項演算子もある
KotlinやScalaには、3項演算子が無い代わりに、ifが式となっています。if式でいいんじゃ…という気持ちになります。
includeとextendは使い分ける
【Ruby】includeとextendの違い。クラスメソッドとインスタンスメソッドの違いと実例。 - Qiita
Scalaのtraitを使うときみたいに、全部extendしてました…。使い分けます。
末尾にnilを置いておくと、Style/GuardClauseで怒られるのを回避できる
def method1
if @variable1.nil?
raise "error1"
end
if @variable2.nil?
raise "error2"
end
if @variable3.nil?
raise "error3"
end
# 以下コードに変更されるのを防げる
# unless @variable3.nil?
# return
# end
#
# "error3"
nil
end
Array#concatは破壊的に連結
なんだってー?!(JavaのString脳、JavaScriptのArray/String脳)
GUIデバッグが標準ではできない
debaseなどのGemを追加で入れないといけなく、GUIデバッグ派の人は、デバッグのための環境構築から入らないといけない。
IntellJでは、debase、VSCodeでは、vscode-rdbgを使う必要がある。
Discussion