スカラ。 はじめに

こんにちはハブラ



少し前、私は珟圚JVMの䞋にある倚くの蚀語の1぀であるScalaに興味を持ちたした。 これには倚くの理由がありたすが、䞻な理由は、cppのような蚀語で䜜業するずきの䞍䟿さの高たり続ける感じです。 私の目はRuby、Groovy、Pythonに亀互に目を向けたしたが、それらはすべお、私の通垞の䜜業タスクにあたり適しおいないツヌルの印象を残したしたPythonは良いですが、型付けされおいない蚀語には独自の制限がありたす。 䞀方、Scalaはかなり良い蚀語のように芋えたした。 ハブでの怜玢ではそれに関する蚘事が芋぀かりたせんでしたいく぀かありたしたが、入門ではなく軜床に眮くため、私は小さなレビュヌを曞いお倧衆ず​​共有するこずにしたした。



無料の博芧䌚における蚀語の哲孊



蚀語の䜜成者が远求する䞻な目暙は䜕ですか 私の態床によるず

たず、互換性。 開発者は、タスクの䞭で、Java蚀語ずの互換性を維持し、さたざたなタスクを解決するためのgovnokodov開発の数千の䟋を蚭定したした。

第二に、䞻にしかし完党にはほど遠いJavaずは異なる機胜的な機胜を備えた蚀語の集䞭的な飜和。

第䞉に、あなたずの私たちの仕事の円滑化。 実際、Scalaコンパむラヌはプログラマヌを1語で理解し、特にラクダではないこずを説明するためのコヌドを曞くために、これたでにチャンスがありたせんでした。

第4に、モゞュヌル化された疎結合の゜フトりェアコンポヌネントの䜜成をサポヌトし、既存のコンポヌネントの幅広い適応オプションず組み合わせるこずを掚奚したす。 目暙は、完党に反察であるずいうこずではなく、同時に達成するために特定の困難を生み出したす。 さお、䜕が起こるか芋おみたしょう。

5番目に、これは䞊行性サポヌトです。 残念ながら、私の手ず頭はこの領域に到達しおいたせんでしたがこれたでのずころ、この点に重点を眮いお、すべおの蚀語リ゜ヌスに垞に取り組んでいたす。



蚀語実隓のために、ここからお気に入りのIDEに適切なプラグむンを配眮しおください。



それでは、蚀語自䜓を芋おみたしょう...



䞀般的な蚀語のアむデア、構文の䟋



おそらく最も重芁なのは、「オブゞェクトの統䞀モデル」です。 この甚語は、著者によっお次のようにデコヌドされたす。「各倀はオブゞェクトであり、各操䜜はメ゜ッド呌び出しです。」 これはもちろん「すべおがオブゞェクト」ではありたせんが、゚ンティティはJavaに比べお枛少しおおり、゚ンティティが少ないほど寿呜は短くなりたす:)適甚された甚語では、これは数字ず蚘号が共通のヒヌプに存圚する䞍倉オブゞェクトになり、すべおの操䜜が参照セマンティクスを取埗したす。 たずえば、 5 + 5



コヌドは非垞に有効であり、ガベヌゞコレクタヌがすぐに投皿するヒヌプ䞊に新しいオブゞェクトを生成したす実際、コンパむラヌがアむデアの深さを理解し、䜕も生成しないこずを静かに願っおいたす:)。



このような高貎な玹介の埌、叀兞的な問題の解決策を芋るこずができたす。

object Main {

def main(args:Array[ String ]) :Unit = {

print( "Hello, " + args(0) + "!" )

}

}








その䞭には次のものがありたす。



さらに、別の短い䟋を芋おみたしょう。

println( ( "Hello, " + args(0) + "!" ).toUpperCase )

println( "Hello, " + args(0) + "!" toUpperCase )








以䞋のように、挔算子の䜿甚.



絶察に必芁ではありたせん。 蚀語の構文では、代わりにスペヌスを䜿甚できたすメ゜ッド匕数は、メ゜ッド名の盎埌に角かっこやカンマなしで蚘述するこずもできたす。 そしお、芋おわかるように、これは非垞に有甚であるこずがわかりたす。最初の行には、優先床の高い挔算子があり.



括匧コヌドを詰たらせお䞍芁なものを曞くようになりたす。2番目の方法では、より簡朔で明確な圢匏で蚘述したす。



開発者ぞの支揎ずしお、Scalaはむンタラクティブモヌドもサポヌトしおいたす。 ぀たり、むンタヌプリタヌを開始しお、コマンドを1぀ず぀入力できたす。 IDEに組み蟌たれたむンタヌプリタヌは䜕らかの理由で定期的に機胜せず、その別のバヌゞョンはUbuntaリポゞトリにありたす。他のディストリビュヌションもうたく機胜しおいるず思いたす。幞せなWindows所有者はい぀ものように苊しむ必芁がありたす:)

$ scala

Welcome to Scala version 2.7.3final (Java HotSpot(TM) Server VM, Java 1.6.0_16).

Type in expressions to have them evaluated.

Type :help for more information.

scala>







非垞に小さな䟋

scala> 1 to 10

res0: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)







ここに、パラメヌタヌを䜿甚したメ゜ッド呌び出しの䟋を瀺したす。 誰も掚枬しなかった堎合、クラスInt



1のオブゞェクトが、同じタむプ10のパラメヌタヌを持぀to



メ゜ッドで呌び出され、結果は倀の範囲になりたす。



別の関数を䜜成しおみたしょう。 圌女に䞎えられた範囲内の数の合蚈を数えおみたしょう

scala> def sum(a: Int, b: Int): Int = {

| var result = 0

| for (i <- a to b) result += i

| result

| }

sum: (Int,Int)Int



scala> sum(1, 5)

res3: Int = 15







他の3぀の重芁なポむントがここに衚瀺されたす。



機胜操䜜



ここで䜕ができたすか はい、䜕でも=関数はプログラムの本栌的なオブゞェクトです。 オブゞェクトのプロパティずしお保存し、パラメヌタず戻り倀ずしお枡し、実行時に実際に䜜成できたす。 これらのプロパティを䜿甚するず、独自の皮類で動䜜するいわゆる高階関数を構築できたす。



説明のために、合蚈を蚈算する叀兞的な䟋を考えおみたしょう。

scala> def sum(f: Int => Int, a: Int, b: Int): Int =

| if (a > b) 0 else f(a) + sum(f, a + 1, b) sum: ((Int) => Int,Int,Int)Int







この䟋では、おなじみの、すべおの和挔算子を衚すsum関数が定矩されおいたす。 パラメヌタには次の意味がありたす。

fは、敎数を合蚈の限界から合蚈の芁玠に倉換する関数です。 パラメヌタヌのタむプの宣蚀に泚意しおください蚘号=>



は、パラメヌタヌが関数であるこずを意味し、受け入れられる倀のタむプはその巊偎の括匧内にリストされたすこの䟋のようにパラメヌタヌが1぀しかない堎合は省略できたす、返される結果のタむプは右偎にありたす。

それは簡単に動䜜したす範囲の䞋限で関数の倀を蚈算し、それを1より小さい範囲で蚈算した結果ず加算したす。

たた、この䟋では、蚀語の別の機胜が衚瀺されたす-倀の匏である堎合ちなみに、以前に䜿甚されたforも匏であり、結果はUnit



型です。 条件が真の堎合、結果は最初のオプションになり、そうでない堎合は2番目のオプションになりたす。

aずbは合蚈の限界です。



ほんの2぀のid



関数ずsquare



関数は、それぞれパラメヌタヌずその正方圢に等しくなりたす。

scala> def id(x: Int): Int = x

id: (Int)Int

scala> def square(x: Int): Int = x * x

square: (Int)Int







ここで、別の叙情的な䜙談を行う必芁がありたす。Scalaの関数には宣蚀スタむルの宣蚀がありたす。 結果を埗る方法ではなく、それが䜕に等しいかを説明しおいたす。 ただし、関数本䜓で逐次蚈算を敎理する堎合、問題はありたせん-ブロックがありたす。



これで、前に曞いた内容を掻甚できたす。

scala> sum(id, 1, 5)

res1: Int = 15

scala> sum(square, 1, 5)

res2: Int = 55







ここで、この郚分のクラむマックスが起こりたす-関数を取埗しお別の関数に枡したす。 むンタヌフェむス、匿名クラス、デリゲヌトはありたせんここにありたす-少しの幞せ。



ここでは、入れ子関数ず匿名関数の䟋を意図的に提䟛せず、カリヌ化しおいたす。 このScalaはすべお実行できたすが、短いレビュヌに含めるこずはできたせん。 䞊蚘の䟋は、プログラミングツヌルずしおの高階関数の重芁性、そしお最も重芁なこずを理解するには十分だず思いたす。 最埌に、プログラミングに関するすばらしい本のこの章を読むこずをお勧めしたす。



クラスの特城



簡単なクラスを説明したしょう。 耇玠数にしたす。 次のコヌドを䜜成したす。

class Complex(r: Double, i: Double) {

def real = r

def image = i

def magnitude = Math .sqrt(r*r + i*i)

def angle = Math .atan2(i, r)



def + (that: Complex) = new Complex( this .real + that.real, this .image + that.image)



override def toString = real+ " + i*" +image+ " | " +magnitude+ "*e^(i*" +angle+ "))"

}



object Main {

def main(args:Array[ String ]) :Unit = {

val first = new Complex(1, 5)

val second = new Complex(2, 4)

val sum = first + second

println(first)

println(second)

println(sum)

}

}








たず、クラスはいく぀かのパラメヌタヌで宣蚀されたす。 続線から掚枬できるように、これらはオブゞェクトの存続期間を通じお利甚可胜なコンストラクタヌパラメヌタヌです。

第二に、いく぀かのメ゜ッドがクラスで宣蚀されおいたす-セレクタヌ。 1぀はデカルト衚珟甚で、もう1぀は極座暙甚です。 ご芧のずおり、どちらもコンストラクタヌパラメヌタヌを䜿甚しおいたす。

第䞉に、加算挔算子がクラスで宣蚀されおいたす。 通垞のメ゜ッドずしお宣蚀され、 Complex



を受け入れお返したす。

そしお最埌に、このクラスでは、すべおのJavaプログラマヌになじみのあるtoString



関数がtoString



たこずは間違いありたせん。 Scalaのオヌバヌラむドメ゜ッドは、垞にoverride



キヌワヌドで明瀺的に指定する必芁があるこずに泚意するこずが重芁です。



非垞に倧きな実甚的䟡倀にもかかわらず、このクラスにはいく぀かの欠点がありたす。



さお、この矎しい蚀語の助けを借りお欠点を修正しおみたしょう。

class Complex(val real: Double, val image: Double) extends Ordered[Complex] {

def magnitude = Math .sqrt(real*real + image*image)

def angle = Math .atan2(image, real)

def + (that: Complex) = new Complex( this .real + that.real, this .image + that.image)

def compare(that: Complex): Int = this .magnitude compare that.magnitude

override def toString = real+ " + i*" +image+ " | " +magnitude+ "*e^(i*" +angle+ "))"

}



object Main {

def main(args:Array[ String ]) :Unit = {

val first = new Complex(1, 5)

val second = new Complex(2, 4)

if (first > second )

println( "First greater" )

if (first < second )

println( "Second greater" )

if (first == second )

println( "They're equal" )

}

}








それで、新機胜



特性のアむデアに぀いおいく぀かの蚀葉を蚀う時が来たした。 これは特別なタむプのクラスであり、コンストラクタヌを持぀こずはできたせんが、メ゜ッドず属性を持぀こずができたす。 通垞、圌らは圌らの可胜な盞続人ずの盞互䜜甚のための䜕らかのプロトコルを確立したす。 このプロトコルを䜿甚しお、子孫から必芁な情報を取埗し、それに䜕らかの動䜜を実装できたす。 したがっお、任意のクラスたたはオブゞェクトを任意の数の特性および1぀のクラスのみから継承できたす。 たずえば、 Ordered



は抜象メ゜ッドを宣蚀し、 compare



それに基づいお継承クラスを挔算子<、<=、>などで補完したす。 ここでは、異なるオブゞェクトの真実を提䟛し、hashCodeを䜿甚したequalsメ゜ッドもそのような堎合に再定矩する必芁があるため、提䟛された==挔算子を再定矩する䟡倀があるこずに泚意しおください。

「これはすべお良いこずです」ずアりト゜ヌシング垂堎の経隓豊富なファむタヌは、「しかし、ナンセンスな属性修食子を䜿甚しお、通垞のドメむンクラスが必芁な堎合はどうなりたすか」

圓然、解決策がありたす:)

class User {

private [ this ] var _name: String = ""

def name = _name toUpperCase

def name_=(name: String ) = {

_name = if (name != null ) name else ""

}

}








これをすべお䜿甚する方法を理解するために、次のコヌドの結果を芋おみたしょう簡朔にするため、ここではオブゞェクトずメむンメ゜ッドの説明は含めたせんでした。

val user = new User( "Scala!!!" )

println(user.name)

user.name = "M. Odersky"

println(user.name)






SCALA!!!

M. ODERSKY









泚意、結論<object>構造を䜿甚するず、<something> _ =ずいう名前のメ゜ッドが呌び出されたす。 私がScalaで知っおいる限り、これは2番目のハックです最初のハックは()



をapply



メ゜ッドの呌び出しに倉換しapply



 。Guidoは挔算子の䜿甚をメ゜ッド呌び出しに暗黙的に倉換するこずを遺蚀したした。



パタヌンマッチング



あなたは遠くから少し始めなければなりたせん。 Scalaには、いわゆるケヌスクラスがありたす圓然、オブゞェクトも。 それらはキヌワヌドcase



で宣蚀され、その埌コンパむラは次のこずを行う自由を取りたす

  1. クラスに䞀臎する名前でコンストラクタヌ関数を䜜成したす。
  2. コンストラクタヌ匕数に基づいお、クラスtoString、equals、hashCodeに実装したす。
  3. すべおのコンストラクタヌ匕数のセレクタヌを䜜成したす。


このすべおの魔法は、 match



メ゜ッドを䜿甚するための道を開きたす。 䟋を芋おみたしょう

abstract class User



case class KnownUser(val name: String ) extends User



case class AnonymousUser() extends User



object Test {

val users = List (KnownUser( "Mark" ), AnonymousUser(), KnownUser( "Phil" ))



def register(user: User): Unit = user match {

case KnownUser(name) => println( "User " + name + " registered" )

case AnonymousUser() => println( "Anonymous user can't be registered" )

}



def main(args: Array[ String ]) =

users. foreach ( register )

}






したがっお、コヌドの党䜓像は次のずおりです。ナヌザヌの抜象クラスがあり、圌のカゞュアルな子孫が2぀ありたす。有名な匿名ナヌザヌです。 ここではファンタゞヌを含む䌚議のナヌザヌのリストを登録したす。 このために、パタヌンマッチングを䜿甚したす。これにより、さたざたな皮類のオブゞェクトに察するメ゜ッドのさたざたな動䜜を決定し、これらのオブゞェクトからのデヌタサンプリングを提䟛できたす。



このような実䟋の埌に、 match



メ゜ッドの動䜜に関する理論がありたす。 ケヌス匏ごずに、型がテンプレヌトクラスず䞀臎するかどうか、およびコンストラクタヌパラメヌタヌがテンプレヌトず䞀臎するかどうかを確認したす。 䞀般的な堎合のテンプレヌトには、次のものが含たれたす。

  1. 他のケヌスクラスのコンストラクタ。 ここではすべおが非垞に再垰的であり、テンプレヌトのネストの深さはプログラマヌの狂気によっお制限されたせん。
  2. テンプレヌト倉数。 これらは、結果を蚈算するために関数の本䜓で利甚可胜になりたす。
  3. シンボル_



    興味のない意味を瀺したす。
  4. 蚀語リテラル。 たずえば、 1



    たたは"Hello"



    です。


したがっお、構造クラスおよび/たたは栌玍されたデヌタに基づいおオブゞェクトから特定の倀を取埗する方法を説明できるツヌルを取埗したす。



OOPの基本原則に粟通しおいる人は、圓然、この問題が仮想関数を䜿甚するこずで完党に解決されるこずにすぐに気付くでしょうさらに、提案されたアプロヌチはベストプラクティスではありたせん。 ただし、その䜿甚には2぀の困難が䌎いたす。たず、倚数のそのような関数を䜿甚するコヌドのサポヌトが耇雑になりたす結局、むベント、グルヌプ、ブログなどでナヌザヌを登録し、それぞれの堎合に仮想メ゜ッドを䜜成したす 、第二に、同じタむプのオブゞェクトは基本的に異なる構造を持぀こずができ、デヌタを提䟛できないずいう事実に関する問題を解決したせん。



2番目の問題に特に泚意を払いたいず思いたす。 䞊蚘のコヌドはJavaではどのようになりたすか 1぀のクラス。匿名ナヌザヌをnull



蚭定し、毎回チェックする堎合私のような麻酔薬はisAnonymousのようなメ゜ッドを開始したす。これは、フィヌルドを同じnull



ず比范するこずで構成されnull



。 問題は明癜です-暗黙的で安党ではありたせん。 オブゞェクトの構造のさたざたなバリ゚ヌションが1぀のクラスに結合され、特定のケヌスで䜿甚されおいないものがnullで詰たっおいる堎合、さらに悪いこずにデフォルト倀が発明された堎合、そのような䟋は非垞に倚くありたす。 Scalaでは、オブゞェクトの構造のバリ゚ヌションを明瀺的に蚘述するこずができ、これらのバリ゚ヌションを操䜜するための䟿利なメカニズムが提䟛されたす。



結論ずしお、この手法を仮想機胜の代替ずしお効果的に適甚できる時期に぀いおのいく぀かの考え



逆はすべおのポむントに圓おはたりたす。たずえば、12個のクラスにパタヌンマッチングを䜿甚するのは良い考えではないようです。



型掚論



既にお気付きだず思いたすが、コヌドでは、クラスずメ゜ッドを宣蚀するずきにのみ型を指定しおいたす。 コヌドブロックでは、ほずんど垞にそれらを省略したした。 実際、プログラマヌが明瀺的に型を指定しない堎合、Scalaはコンテキストから型を決定しようずしたす。 たずえば、 def s = "Scala"



定矩で定数倀を初期化するずきdef s = "Scala"



コンパむラは定数のタむプを文字列ずしお決定したす。 これはすべお、ゞェネリック型でも機胜したす。たずえば、䞊蚘のval users = List(KnownUser("Mark"), AnonymousUser(), KnownUser("Phil"))



は、タむプList[User]



定数を䜜成し、自動的に階局の適切なレベルに䞊がりたす継承し、それを䜿甚しおコンテナタむプをパラメヌタ化したす。 実際には、これは、そのような広告を倧幅に節玄できるこずを意味したす楜しみのために、JavaたたはCで同じコヌドを蚘述しおください:)。



おわりに



うヌん...投皿の開始たでに、長い間スクロヌルしたす。 明らかにそれは終了する時間です。 そしお、私はもっず倚くのこずを蚀いたい䞀般化されたクラスを蚘述するための最も興味深いメカニズムに぀いお、暗黙の倉換に぀いお、そしおそれらが実際に明瀺的で、定数の遅延初期化であるずいう事実に぀いお。



私自身は、マルチスレッドモデルずその実装に特有の䞀連のプリミティブをただ調査しおおらず、xml蚀語サポヌトを扱い、DSL構造を操䜜し、䞻力プロゞェクトであるLiftを芋お...



ただし、いく぀かの結論を立おるこずを敢えおしたす。



以䞊です。 批刀は倧歓迎です。

最埌に、倧衆ぞの質問このトピックは興味深いですか、続線を曞く䟡倀がありたすか



UPDこれを手䌝っおくれたみんなに感謝しお、文法を修正したした。 特に、倧芏暡なコンマ甚のganqqwerty 。



_________

゜ヌスコヌドハむラむタヌですべおの゜ヌスコヌドが匷調衚瀺されたした。

テキストはHabraで準備されたす



All Articles