ムカデノワラジ

ムカデノワラジ

ガジェット・Webサービス・プログラミング・エンタメについて書く雑記ブログ

MENU

scalaとruby比較メモ

Scala関数型プログラミングのようにも書けますが、オブジェクト指向プログラミングの様にも書けます。Ruby経験者からするとScalaの文法や組み込みはなじみやすいものが多いです。Rubyのように配列やHashでつかえる繰り返し処理用のメソッドが非常に充実しています。多くの処理をfor文やif文を使うことなく実装できます。

 

Scalaは関数型の特性を生かして副作用のない処理もできますし、オブジェクト指向のような直感的な設計もできます。このような特徴がありますがScalaのイイところはRubyのように楽しくプログラミングができるように設計されていることだと思います。

 

Scalaは静的型付け言語ですが、sbt runコマンドを使ってローカルサーバーを立てるとファイル変更ごとに逐一コンパイルが走るのでまるでRuby on Railsをつかっているような開発体験ができます。

JavaScalaウェブアプリケーションフレームワークPlay FrameworkはRuby on Railsライクなフレームワークです。ですがPlay Framework はRailsと比べて暗黙の規約が少なく、自由度も高いため結果として覚えるべきルールが少なくて済みます。

この記事ではRuby から Scalaにスムーズに移行できるようメモにまとめます。

Scalaを勉強するならコップ本として有名なScalaスケーラブルプログラミングがおすすめです。 

Scalaスケーラブルプログラミング第3版

Scalaスケーラブルプログラミング第3版

 

 

メジャーなウェブアプリケーションフレームワーク

MVC

ruby rails

scala play

RubyはModel,View,Controllerのそれぞれに関して暗黙・自動で処理される部分が多い。

ScalaはView, ControllerについてはRubyと感覚が近いが、Modelやdb周りはまだ結構手を動かさないといけない。

RubyでいうActive RecordのようなライブラリとしてSlickがある。JavaユーザーならJDBCも使える。

 

Controllerとアクション

controllerの基本形

Ruby

class HogeController

  def index

  end

end

 

Scala

@Singleton

class HogeController @Inject() extends Controller{

  def index = Action {

       Ok(views.html.index())

  }

}

 

パラメーターを受け取る

Rudy

params[:hoge] から取得できる

Scala

アクションに設定する

class HomeController @Inject () extends {

def receiveParams(a: String) = Action {

     // 処理

     }

}

GET   /receiveParams     controllers.HomeController.receiveParams(a: String = "default" )

// String型は省略しても良い

// conf/routes

//拡張子は無い。railsでいうconfig/routes.rb

 

・テンプレートを表示する

Ruby

class HomeController 

def hello

 @message = "hello world"

end

#自動でhome/hello.html.erbを表示

viewで<%= @message =%>で表示

Scala

def hello() = Action{ implicit request: AbstractController[AnyContent]  =>

  val message: String="hello world"

   Ok(views.html.hello(message))

}

// hello.scala.htmlを表示

htmlの先頭に

@(message: String)

//html中で@messageで表示

 // HTMLの中にScala,Scalaの中にHTMLがナチュラルに書ける

・文字列を返す

Ruby

class HomeController

  def hello

     render plain: "hello world"

  end

end

get '/home/hello', to: 'home#hello'

 

Scala

def hello=Action {

   Ok("hello world")

}

GET    /hello     controllers.HomeController.hello

 

・リダイレクト

Ruby

redirect_to hoge_path

Scala

Redirect("/hoge")

 

文法

コメント

ruby のコメント

// scala のコメント

変数

ruby

x=1

scala

// 再代入可

var x=1 

// 再代入付加

val x = 1

 

クラス

ruby

class Hoge

  def initialize(x)

    @x = x

  end

  def plus(y)

    @x + y 

  end

end

x =Hoge.new(1)

x.plus(2)

#()を省略して x.plus 2という記法も可

#=> 3

 

scala

case class Hoge(x: Int){

  def plus(y: Int): Int = {

     x+y

  }

}

 x= Hoge(1)

x.plus(2)

//.と()を省略して x plus 2 という記法も可

// 3

可変長引数

Ruby

def printAll(*s)

  p *s

end

printAll("foo","bar","baz") # foo bar baz => ["foo","bar","buz"]

 

Scala

def printAll(s: String*): Unit = {

  s.foreach(println)

}

printAll("foo","bar","baz") // foo bar baz

 

配列

ScalaにはArrayもあるが再代入できないListを使うほうがScala向き

Ruby

[1,2,3,4,5]

Scala

List(1,2,3,4,5)

Ruby

list = [1,2,3,4,5]

list << 6

#=> list = [1,2,3,4,5,6]

Scala

val list = List(1,2,3,4,5)

list:+ 6

// List(1,2,3,4,5,6)

0 +: list

// List(0,1,2,3,4,5)

 

 

Ruby

(1..5).to_a

#=> [1,2,3,4,5]

Scala

Range(1..6).toList

(1 to 5).toList

// List[Int]= List(1,2,3,4,5)

 

Ruby

Array.new(5,1)

=> [1,1,1,1,1]

Scala

List.fill(5)(1)

// List(1,1,1,1,1)

 

Ruby

[1,1,1,1,1].sum

#=> 5

Scala

List(1,1,1,1,1).sum

// 5

 

Ruby

[1,2,3,4,5].inject(:*)

#=> 120

Scala

List(1,2,3,4,5).product

// 120

 

Ruby

[1,2,3,4,5].map{|n| n/2}

#=>[0,1,1,2,2]

Scala

List(1,2,3,4,5).map(_/2)

// List(0,1,1,2,2)

List(1,2,3,4,5).map{n => n/2}

//List(0,1,1,2,2)

val listOfLists=List(List(1,2),List(3,4),List(5,6))

listOfLists.map(_.map(_*2))

// List(List(2,4),List(6,8),List(10,12))

 

 

Ruby

[1,2,3,4,5].each{|n| p n}

Scala

List(1,2,3,4,5).foreach{n => print(n)}

// _をつかうと引数名を省略して記述できる

List(1,2,3,4,5).foreach(print(_))

// 12345

 

Ruby

[1,2,3,4,5].select{|n| n%2 ==0 }

#=> [2,4]

Scala

List(1,2,3,4,5).filter(_%2==0)

List(1,2,3,4,5).filter{n=> n%2 ==0}

// List(2,4)

 

Ruby

[1,2,3,4,5].count{|n| n>2}

#=> 3

Scala

List(1,2,3,4,5).count(_>2)

// 3

 

Ruby

def fib(n)

  n<2 ? n : fib(n-1) + fib(n-2)

end

fib(30)

#=> 832040

Scala

def fib(n: Int): BigInt = if (n<2) n else fib(n-1) + fib(n-2)

fib(30)

// 832040

 

 

Ruby

[[1,2],[3,4],[5,6]].map{|n,m| n*m}

#=>[2,12,30]

Scala

Seq( (1,2),(3,4),(5,6)).map{case(p,q) => p*q}

// List(2,12,30)

 

 

Ruby

[1,2,3,4,5,6,7,8,9].each_slice(3){|ar| p ar}

#=>[1,2,3]

#=>[4,5,6]

#=>[7,8,9]

Scala

List(1,2,3,4,5,6,7,8,9).grouped(3).foreach{ar => println(ar)}

// List(1,2,3)

// List(4,5,6)

// List(7,8,9)

 

参考サイト

Scala の省略ルール早覚え · GitHub

Scala PlayFramework でアプリケーション作ってみた。② 【Controller(View)編】 - yujiro's blog

2日目 · Scala研修テキスト

Play frameworkことはじめ - Qiita

Play Frameworkハンズオン - Qiita

Scala入門時に役立つ情報まとめ - Qiita

RailsエンジニアのためのPlay Framework入門 - Qiita

www.playframework.com