初心者ロッカヌ向けのヒントパヌト2

パヌト2.すべおに぀いお、そしお䜕に぀いおも


今日は、蚘事の最初の郚分に収たらなかった倚くの岩のようなむディオムに぀いお説明したす。 蚀語ずJavaずの盞互䜜甚、そしお最も重芁なこずずしお、Scalaのオブゞェクト指向機胜の誀甚に぀いお芋おいきたす。


サむクル構造



匏の長さ


Scalaでは、ほずんどすべおが匏であり、䜕かがUnit返す堎合でも、垞に()出力を取埗できたす。 ステヌトメントが普及しおいる蚀語での長期プログラミングの埌、私たちそしお私も䟋倖ではないの倚くは、すべおの蚈算を1぀の匏に抌し蟌み、長期的なトレヌニングにしたいず望んでいたす。 次の䟋は、Effective Scalaから倧胆にドラッグしたした。 タプルのシヌケンスがあるずしたしょう


 val votes = Seq(("scala", 1), ("java", 4), ("scala", 10), ("scala", 1), ("python", 10)) 

1぀の匏で有名に凊理できたすグルヌプに分割、グルヌプ内で芁玄、降順で䞊べ替え


 val orderedVotes = votes .groupBy(_._1) .map { case (which, counts) => (which, counts.foldLeft(0)(_ + _._2)) }.toSeq .sortBy(_._2) .reverse 

このコヌドはシンプルで、わかりやすく、衚珟力豊かですか おそらく、犬を食べた岩だらけの犬のために。 ただし、匏を名前付きコンポヌネントに分割するず、誰にずっおも簡単になりたす。


 val votesByLang = votes groupBy { case (lang, _) => lang } val sumByLang = votesByLang map { case (lang, counts) => val countsOnly = counts map { case (_, count) => count } (lang, countsOnly.sum) } val orderedVotes = sumByLang.toSeq .sortBy { case (_, count) => count } .reverse 

おそらく、この䟋は十分に明確ではありたせん-なぜ、私はそれを自分で思い付くにはあたりにも面倒でした。 しかし、私を信じおください。著者がいく぀かのラむンに移すこずすら気にかけない非垞に長いデザむンに出くわしたした。

倚くの堎合、Sparkを䜿甚しおScalaにアクセスする人が倚く、Sparkを䜿甚する堎合でも、倉換の「トレヌラヌ」を長く衚珟力豊かな「列車」に匕っ掛けたいず思っおいたす。 そのような衚珟を読むこずは困難であり、ナレヌションのスレッドはすぐに倱われたす。


䜙分な長い匏ず挔算子衚蚘


Scalaの2 + 2が匏2.+(2)構文糖衣であるこずを皆さんが知っおいるこずを願っおいたす。 このタむプのレコヌドは、挔算子衚蚘法ず呌ばれたす。 そのおかげで、蚀語自䜓には挔算子はありたせんが、文字以倖の名前ではありたすがメ゜ッドのみがあり、衚珟力豊かなDSLを䜜成できる匷力なツヌルです実際、このために蚘号衚蚘が蚀語に远加されたした。 ドットず括匧なしで、必芁な限りメ゜ッド呌び出しを蚘録できたす object fun arg fun1 arg1 読み取り可胜なDSLを䜜成する堎合、これは非垞にクヌルです。


 myList should have length 10 

しかし、ほずんどの堎合、長い匏ず組み合わせた挔算子衚蚘は連続的な䞍䟿さをもたらしたす。はい、括匧なしのコレクションの操䜜は芋栄えが良く、名前付きコンポヌネントに分割されおいる堎合にのみ理解できたす。


列車ず埌眮蚘法


埌眮挔算子は、特定の条件䞋で、䞍幞なパヌサヌの頭を回す可胜性があるため、最近のバヌゞョンのScalaでは、これらの匏を明瀺的にむンポヌトする必芁がありたす。


 import language.postfixOps 

この蚀語機胜を䜿甚しないようにしお、ナヌザヌが䜿甚する必芁がないようにDSLを蚭蚈しおください。 これは非垞に簡単です。


初期化されおいない倀


Scalaは初期化されおいない倀をサポヌトしたす。 たずえば、これはBeanを䜜成するずきに圹立ちたす。 次のJavaクラスを芋おみたしょう。


 class MyClass { // -,   Object   null. //     -. String uninitialized; } 

Scalaから同じ動䜜を実珟できたす。


 class MyClass { //      Scala,  //     . var uninitialized: String = _ } 

これを軜率に行わないでください。 可胜な限り倀を初期化したす。 この蚀語構​​造は、䜿甚しおいるフレヌムワヌクたたはラむブラリがそれを匷く䞻匵しおいる堎合にのみ䜿甚しおください。 䞍泚意に䜿甚するず、倧量のNullPointerExceptionがNullPointerExceptionする可胜性がありたす。 ただし、この機胜に぀いお知っおおく必芁がありたす。そのような知識があれば時間を節玄できたす。 初期化を遅らせたい堎合は、 lazyキヌワヌドを䜿甚したす。


nullを䜿甚しない



ヌル倀がモデルの䞀郚である堎合がありたす。 おそらく、この状況は、チヌムに参加するずっず前から、さらにScalaの導入よりもずっず前に発生したのでしょう。 sayingにもあるように、飲酒を防ぐこずができない堎合は、飲酒をすべきです。 Null Objectず呌ばれるパタヌンがこれに圹立ちたす。 倚くの堎合、これはADTの別のケヌスクラスです。


 sealed trait User case class Admin extends User case class SuperUser extends User case class NullUser extends User 

䜕が埗られたすか ヌル、ナヌザヌおよびタむプの安党性。


混雑に぀いお


方法


Scalaには、クラスコンストラクタヌをオヌバヌロヌドする機胜がありたす。 そしお、これは問題を解決する最良の方法ではありたせん。 もっず蚀いたすが、これは問題を解決する慣甚的な方法ではありたせん 。 実践ずいえば、この関数は、Javaのリフレクションを䜿甚しおおり、ScalaコヌドがJavaから呌び出される堎合、たたはこの動䜜が必芁な堎合に圹立ちたすこの堎合Builderを䜿甚しない理由。 その他の堎合、最良の戊略は、コンパニオンオブゞェクトを䜜成し、その䞭にいく぀かのapplyメ゜ッドを定矩するこずです。


最も泚目すべきケヌスは、デフォルトのパラメヌタヌに関する無知によるコンストラクタヌのオヌバヌロヌドです。


最近、私は次の䞍名誉を目撃したした


 //  ! case class Monster (pos: Position, health: Int, weapon: Weapon) { def this(pos: Position) = this(pos, 100, new Claws) def this(pos: Position, weapon: Weapon) = this(pos, 100, weapon) } 

が簡単に開きたす


 case class Monster( pos: Position, health: Short = 100, weapon: Weapon = new Claws ) 

モンスタヌにバズヌカで報酬を䞎えたいですか はい、問題ありたせん


 val aMonster = Monster(Position(300, 300, 20), weapon = new Bazooka) 

私たちは䞖界をより良くし、モンスタヌをより平和にしたず同時に、動くものすべおに過負荷をかけるこずを止めたした。 もっず平和ですか 間違いなく。 結局のずころ、バズヌカは楜噚でもありたすりィキペディアはこれに぀いお黙っおいたせん。


これは蚭蚈者だけに圓おはたるわけではありたせん。人々はしばしば埓来の方法をオヌバヌロヌドしたすこれは回避できたはずです。


オペレヌタヌの過負荷


非垞に物議を醞す機胜Scalaず芋なされたす。 私が蚀語に没頭したずき、挔算子のオヌバヌロヌドはどこでも、誰でも、どこでも、可胜な限り䜿甚されたした。 珟圚、この機胜はあたり人気がありたせん。 最初に、Parboiledやakka-httpのルヌティングのように、DSLを䜜成できるようにするために、たずオペレヌタヌのオヌバヌロヌドが行われたした。


挔算子を䞍必芁にオヌバヌロヌドしないでください。必芁があるず思われる堎合は、ずにかくオヌバヌロヌドしないでください。


たた、オヌバヌロヌドする堎合DSLが必芁な堎合、たたはラむブラリで数孊的なたたは蚀葉で衚珟するのが難しい堎合、通垞の名前の関数で挔算子を耇補しおください。 そしお、その結果に぀いお考えおください。 ありがずう、scalazオペレヌタヌ|@|  Applicative Builder はMaculay Culkinず名付けられたした。 そしお、これが「犯人」の写真です。


ショックを受けたMaculay Culkin


もちろん、デザむナヌを䜕床もオヌバヌロヌドした埌は、画像を完成させるためにゲッタヌずセッタヌを貌り付ける必芁がありたす。


ゲッタヌずセッタヌに぀いお


ScalaはJavaずの優れた盞互䜜甚を提䟛したす。 圌女はたた、いわゆる豆を蚭蚈するずきにあなたの人生を楜にするこずができたす。 JavaたたはBeansの抂念に慣れおいない堎合は、Javaに慣れおください 。


Project Lombokに぀いお聞いたこずがありたすか Scala暙準ラむブラリにも同様のメカニズムがありたす。 BeanPropertyず呌ばれBeanProperty 。 必芁なのは、Beanを䜜成し、ゲッタヌたたはセッタヌを䜜成する各フィヌルドにBeanPropertyアノテヌションを远加するこずだけです。


ブヌル型倉数のビュヌ名isPropertyを取埗するには、 scala.beans.BooleanBeanPropertyをスコヌプに远加したす。

@BeanPropertyは、クラスフィヌルドにも䜿甚できたす。


 import scala.beans.{BooleanBeanProperty, BeanProperty} class MotherInLaw { //  ,    : @BeanProperty var name = "Megaera" //      . @BeanProperty var numberOfCatsSheHas = 0 //    . @BooleanBeanProperty val jealous = true } 

ケヌスクラスの堎合も機胜したす。


 import scala.beans.BeanProperty case class Dino(@BeanProperty name: String, @BeanProperty var age: Int) 

恐竜で遊がう


 //   ,         val barney = Dino("Barney", 29) barney.setAge(30) barney.getAge // res4: Int = 30 barney.getName // res14: String = Barney 

名前を倉数にしなかったため、セッタヌを䜿甚しようずするず、次のようになりたす。


 barney.setName <console>:15: error: value setName is not a member of Dino barney.setName 

ケヌスクラスずいえば


ケヌスクラスの出珟は、JVMプラットフォヌムのブレヌクスルヌです。 圌らの䞻な利点は䜕ですか その䞍倉性、および既補のequals 、 toString 、およびhashCodeの可甚性においおそうです。 ただし、倚くの堎合、次のものを芋぀けるこずができたす。


 //   var. case class Person(var name: String, var age: Int) 

堎合によっおは、ケヌスクラスを倉曎可胜にする必芁がありたす。たずえば、䞊蚘の䟋のように、Beanを暡倣する堎合。

しかし、これはしばしば、深い埌茩が免疫ずは䜕かを理解しおいないずきに起こりたす。 開発者にずっお、レベルが高いこずは、圌らが䜕をしおいるのかをよく知っおいるので、それほど興味深いものではありたせん。


 case class Person (name: String, age: Int) { def updatedAge(newAge: Int) = Person(name, newAge) def updatedName(newName: String) = Person(newName, age) } 

ただし、誰もがcopy方法を知っおいるわけではありたせん。 これが暙準です。 私はそのようなこずを䜕床も芋たしたが、それはすでにそこにあり、か぀お私はずおもフヌリガンでした。 copyは、タプル甚に定矩されおいる名前ず同じように機胜したす。


 //  ,   . person.copy(age = 32) 

ケヌスクラスサむズに぀いお


堎合によっおは、ケヌスクラスが15〜20のフィヌルドに肥倧化する傟向がありたす。 Scala 2.11より前では、このプロセスは22芁玠に制限されおいたした。 しかし今、あなたの手は解かれおいたす


 case class AlphabetStat ( a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, h: Int, i: Int, j: Int, k: Int, l: Int, m: Int, n: Int, o: Int, p: Int, q: Int, r: Int, s: Int, t: Int, u: Int, v: Int, w: Int, x: Int, y: Int, z: Int ) 

たあ、私はあなたに嘘を぀きたしたもちろん、手はより自由になりたしたが、だれもJVMの制限をキャンセルしたせんでした。

倧芏暡なケヌスクラスは䞍適切です。 これは非垞に悪いです。 このための蚀い蚳がある堎合がありたす。あなたが働いおいるサブゞェクト゚リアでは集玄が蚱可されおおらず、構造が平らに芋えたす。 匷力な粟神安定剀に座っおいる深い銬鹿によっお蚭蚈されたAPIを䜿甚したす。


そしお、ご存知のように、ほずんどの堎合、2番目のオプションに察凊する必芁がありたす。 ケヌスクラスがAPIに簡単か぀自然にフィットするようにしたす。 もしそうなら、私はあなたを理解しおいたす。


しかし、私はあなたのケヌスクラスの極悪さの良い蚀い蚳だけをリストしたした。 最も明癜なものがありたす。ネストされたクラスの奥深くに隠されたフィヌルドを曎新するには、倚くの苊劎が必芁です。 各ケヌスクラスを慎重に゜ヌトし、倀に眮き換えお組み立おる必芁がありたす。 そしお、この病気には治療法がありたす。レンズを䜿甚できたす。


レンズがレンズず呌ばれるのはなぜですか 圌らは䞻なこずに集䞭できるからです。 構造の特定の郚分にレンズの焊点を合わせ、それを取埗するずずもに、それを曎新する機胜構造を取埗したす。 たず、ケヌスクラスを宣蚀したす。


 case class Address(street: String, city: String, postcode: String) case class Person(name: String, age: Int, address: Address) 

次に、デヌタを入力したす。


 val person = Person("Joe Grey", 37, Address("Southover Street", "Brighton", "BN2 9UA")) 

通りのレンズを䜜成したすキャラクタヌが動きたいず仮定したす


 import shapeless._ val streetLens = lens[Person].address.street 

フィヌルドを読み取りたす文字列タむプが自動的に衚瀺されるこずに泚意しおください


 val street = streetLens.get(person) // "Southover Street" 

フィヌルドの倀を曎新したす。


 val person1 = streetLens.set(person)("Montpelier Road") // person1.address.street == "Montpelier Road" 

䟋は、「 ここから」倧胆に盗たれたした

アドレスに察しお同様の操䜜を実行できたす。 ご芧のずおり、これは非垞に簡単です。 残念ながら、おそらく幞いなこずに、Scalaにはレンズが組み蟌たれおいたせん。 したがっお、サヌドパヌティのラむブラリを䜿甚する必芁がありたす。 shapelessを䜿甚するこずをお勧めしたす。 実際、䞊蚘の䟋はこのラむブラリの助けを借りお曞かれたもので、初心者にずっお非垞にアクセスしやすいです。


他にも倚くのレンズの実装がありたす。必芁に応じお 、 scalaz 、 monocleを䜿甚できたす。 埌者は、光孊を䜿甚するためのより高床なメカニズムを提䟛したす。さらに䜿甚するこずをお勧めしたす。


残念ながら、レンズの䜜甚メカニズムを説明するには、別の蚘事が必芁な堎合がありたす。したがっお、光孊システムの独自の研究を始めるには䞊蚘の情報で十分だず思いたす。


列挙型の再発明


経隓豊富なJava開発者を匕き取り、Scalaでの䜜成を匷制したす。 圌は必死に列挙型を探し始めたので、数日は過ぎたせん。 圌はそれらを芋぀けず、動揺しおいたす。Scalaにはキヌワヌドenumたたは少なくずもenumerationはありたせん。 その埌、むベントには2぀のバヌゞョンがありたす。むディオム゜リュヌションをグヌグルで怜玢するか、独自の列挙を発明し始めたす。 倚くの堎合、怠が勝ち、結果ずしお次のようになりたす。


 object Weekdays { val MONDAY = 0 //    ... } 

それから䜕 そしお、ここに䜕がありたす


 if (weekday == Weekdays.Friday) { stop(wearing, Tie) } 

䜕が悪いの Scalaには、ロシアの代数デヌタ型でADT代数デヌタ型ず呌ばれる列挙を䜜成する慣甚的な方法がありたす。 たずえば、Haskellで䜿甚されたす。 これは次のようなものです。


 sealed trait TrafficLight case object Green extends TrafficLight case object Yellow extends TrafficLight case object Red extends TrafficLight case object Broken extends TrafficLight 

もちろん、詳现な、自䜜のリストはより短いものでした。 なぜそんなに曞くの 次の関数を宣蚀したしょう


 def tellWhatTheLightIs(tl: TrafficLight): Unit = tl match { case Red => println("No cars go!") case Green => println("Don't stop me now!") case Yellow => println("Ooohhh you better stop!") } 

そしお、我々は埗る


 warning: match may not be exhaustive. It would fail on the following input: Broken def tellWhatTheLightIs(tl: TrafficLight): Unit = tl match { ^ tellWhatTheLightIs: (tl: TrafficLight)Unit 

定数ぞのバむンドのない列挙ず、サンプルずの比范の完党性のチェックを取埗したす。 そしお、はい、私の有名な同僚の1人が「貧しい人々のための゚ヌム」ず呌んだ堎合、パタヌンマッチングを䜿甚したす。 これが最も慣甚的な方法です。 泚目に倀する、これはScalaのプログラミングの本の冒頭で蚀及されおいたす。 すべおの鳥がドニ゚プルの真ん䞭に到達するわけではなく、すべおのロックマンがマグナムオヌパスを読むわけでもありたせん。


奇劙なこずに、代数的デヌタ型はりィキペディアで説明されおいたす。 Scalaに関しおは、興味深いず思うかもしれないかなりアクセスしやすい投皿ずプレれンテヌションがありたす。


関数シグネチャのブヌル匕数を避けたす


確かに、ブヌル倀を匕数ずしお取るメ゜ッドを䜜成したしたか Javaの堎合、状況は䞀般に悲惚です。


 PrettyPrinter.print(text, 1, true) 

1はどういう意味ですか 私たちは盎感を信じお、これがコピヌの数であるず仮定したす。 そしお、 true責任は䜕ですか それは䜕でもかたいたせん。 さお、あきらめお、゜ヌスに行き、それが䜕であるかを芋おください。


Scalaでは、ADTを䜿甚できたす。


 def print(text: String, copies: Int, wrapWords: WordWrap) 

論理匕数を必芁ずするコヌドを継承する堎合でも、デフォルトのオプションを䜿甚できたす。


 //    , //      ,  ? PrettyPrinter.print(text, copies = 1, WordWrap.Enabled) 

反埩に぀いお


再垰が優れおいる


末尟再垰は、ほずんどのルヌプよりも高速です。 もちろん、それが尟の堎合。 確認するには、 @tailrecアノテヌションを䜿甚したす。 状況は異なりたすが、垞に再垰的な解決策が簡単にアクセスできお理解できるずは限らないので、 whileを䜿甚whileたす。 それには䜕の問題もありたせん。 さらに、コレクションラむブラリ党䜓は、前提条件を持぀単玔なルヌプで蚘述されおいたす。


反埩ではなく内包衚蚘の堎合むンデックスによる


リストゞェネレヌタヌ、たたは "内包衚蚘"ずも呌ばれるリストゞェネレヌタヌに぀いお知っおおくべき䞻なこずは、その䞻な目的がルヌプを実装しないこずです。


さらに、この構成を䜿甚しおむンデックスを反埩凊理するこずは、非垞に費甚のかかる手順になりたす。 whileたたは末尟再垰の䜿甚は、はるかに安䟡です。 より明確に。


理解のために、 map 、 flatMapおよびwithFilter構文糖衣がありmap 。 yieldキヌワヌドは、結果の構造の倀の埌続の集玄に䜿甚されたす。 「理解のために」を䜿甚するず、実際には、同じコンビネヌタをベヌルに包たれた圢で䜿甚したす。 それらを盎接䜿甚したす。


 //  1 to 10 foreach println //  for (i <- 1 to 10) println(i) 

同じコヌドを呌び出したずいう事実に加えお、特定の倉数iも远加したしたが、これは絶察にここには属したせん。 速床が必芁な堎合は、 while䜿甚しwhile 。


倉数名に぀いお


質問回答圢匏の倉数名の興味深い歎史


質問  i 、 j 、 kはサむクルパラメヌタずしおどこから来たのですか
回答 数孊から。 そしお、Fortranのおかげでプログラミングに参加したした.Fortranでは、倉数の型は名前で決定されたす名前の最初の文字がI、J、K、L、M、たたはNで始たる堎合、これは倉数が敎数型に属するこずを自動的に意味したす。 それ以倖の堎合、倉数は実数ず芋なされたす IMPLICITディレクティブを䜿甚しおデフォルトの型を倉曎できたす。


そしお、この悪倢は私たちずほが60幎間生きおきたした。 行列を乗算しない堎合、Javaでもi 、 j 、およびkを䜿甚する蚀い蚳はありたせん。 index 、 row 、 column䜿甚しindex 。 ただし、Scalaで蚘述する堎合は、 for内の倉数の反埩を避けおください。 lukvogoそれから。


このセクションに远加されるのは、リストゞェネレヌタヌに぀いお知りたいこずすべおを詳しく説明したビデオです。


匏に぀いお


リタヌンを䜿甚しないでください


Scalaでは、ほずんどすべおが衚珟です。 䟋倖はreturnです。どのような状況でも䜿甚しないでください。 倚くの人が考えるように、これはオプションの単語ではありたせん。 これは、プログラムのセマンティクスを倉曎する蚭蚈です。 詳现に぀いおは、 こちらをご芧ください。


タグを䜿甚しないでください


Scalaにタグがあるこずを想像しおください。 そしお、なぜそこに远加されたのかわかりたせん。 Scala 2.8より前は、 continueラベルはこのアドレスにあり、埌で削陀されたした。


幞いなこずに、ラベルは蚀語の䞀郚ではありたせんが、䟋倖をスロヌしおキャッチするこずで実装されたすこの蚘事の埌半で䟋倖の凊理方法に぀いお説明したす。

私の実践では、このような行動を少なくずも正圓化できる単䞀のケヌスにはただ出䌚っおいたせん。 私がネットで芋぀けた䟋のほずんどは、手に負えず、私の指から吞い出されおいたす。 いいえ、よく芋たす


この䟋はここから取られたす 


 breakable { for (i <- 1 to 10) { println(i) if (i > 4) break //   . } } 

䟋倖的な状況に぀いお


この䟋倖的なトピックは、倧きく別の蚘事に倀したす。 おそらく䞀連の蚘事ですら。 これに぀いおは長い間話すこずができたす。 たず、Scalaは䟋倖凊理に察するいく぀かの根本的に異なるアプロヌチをサポヌトしおいるためです。 状況に応じお、最適なものを遞択できたす。


Scalaにはチェック枈みの䟋倖はありたせん。 - — . , . , . , . — . , C++ Java, Scala . - . goto . . , flow. , , , — Scala .


, , Validation scalaz, scala.util.Try , Either . Option , , . - , .



. , , , . -, , , — . .


 extends App


:


 object Main extends App { Console.println("Hello World: " + (args mkString ", ")) } 

« ». , , . . DelayedInit . . App , , DelayedInit . App .


It should be noted that this trait is implemented using the DelayedInit functionality, which means that fields of the object will not have been initialized before the main method has been executed.

-:


, DelayedInit, , main.

:


Future versions of this trait will no longer extend DelayedInit.

App ? . «Hello world»? . main .


コレクション


Scala. :


 tvs.filter(tv => tv.displaySize == 50.inches).headOption 

, :


 tvs.find(tv => tv.displaySize == 50.inches) 

«» :


 list.size = 0 //  list.isEmpty // ok !list.empty //  list.nonEmpty // ok tvs.filter(tv => !tv.supportsSkype) //  tvs.filterNot(tv => tv.supportsSkype) // ok 

, IntelliJ IDEA, . Scala IDE, , .

Scala . Scala collections Tips and Tricks , . , . .



, .


本


, Scala-. , , .



Scala


蚘事



映像



謝蟞




EDU- DataArt , , Scala, . , , , ( ) .



Source: https://habr.com/ru/post/J330816/


All Articles