第二章.コートリンきそ


2.1基本要素:関数と変数


2.1.1 Hello, World !

fun main(args: Array<String>) {
    println("Hello, world!")
}
  • 関数の宣言にfunキーワード
  • を使用
  • パラメータ名の後にパラメータタイプを書きます.
  • 最上位レベルで定義できる
  • 関数/javaとは異なり、クラスに関数を入れる必要はありません.
  • 配列も一般的なクラスであり、javaとは異なり、cottlinには配列処理に使用される構文はありません.
  • System.out.printlnの代わりにprintlnを使用します.
  • の末尾でセミコロンを省略できます.
  • 2.1.2関数



    ✅ 文と式の区別
  • 文(statement)は、自分が囲む一番奥のブロックの最上位要素であり、値は生成されません.
  • 式(式)は、値を生成し、他の形式のサブ要素として計算に参加することができる.
  • コトリンではifは式です.△ドアではありません.Javaでは、すべての制御構造は文(statement)ですが、コトリンではループを除いて、ほとんどの制御構造は式です.
    逆に,代入文はJavaでは式であり,コトリンでは文(statement)である.

    関数#カンスウ#

    
    // 블록이 본문인 함수
    fun maxEx1(a: Int, b: Int) : Int {
        return if (a > b) a else b
    }
    
    // 식이 본문인 함수
    fun maxEx2(a: Int, b:Int) : Int = if (a>b) a else b
    
    // 반환 타입을 생략한 함수
    fun maxEx3(a: Int, b:Int) = if (a>b) a else b
    

  • ブロックが本文の関数:本文が括弧の関数

  • 数式が本文の関数:等号と数式からなる関数

  • なぜ戻りタイプを省略できるのか(式が本明細書の関数の戻りタイプであることを省略するしかない)
    コトリンは静的タイプ化言語であり、コンパイル時にすべてのタイプを指定する必要があります.ただし、式が本文の関数の場合、コンパイラは戻りタイプを書く必要はありません.関数の本文を分析することで、結果タイプを関数戻りタイプとして決定します.→類型推定が可能です.
  • 2.1.3変数

    // 타입 생략
    val answer = 42
    // 타입 명시
    val answer: Int = 42

    可変変数と非可変変数

  • val:可変参照を格納する変数valとして宣言された変数が初期化されるとjavaのfinalなどの再インポートできません.
  • var:可変参照、変数の値を変更できます.
  • Javaの一般変数に対応
    デフォルトでは、すべての変数がval、不変変数として宣言され、必要に応じてvarに変更することを推奨します.
    可変参照オブジェクトと可変オブジェクトを割り当て効果のない関数と組み合わせて使用すると、コードは関数型コードに近づきます.
  • valリファレンス自体は変更されませんが、リファレンスが指すオブジェクトの内部値が変更される場合があります.
  • val languages = arrayListOf("Java")   // 불변 참조를 선언
    languages.add("Kotlin")   // 참조가 가리키는 객체 내부 변경
  • varキーワードを使用して変数値を変更し、変数タイプは固定されます.
  • コンパイラは、変数宣言点の初期化方式から変数のタイプを推定し、変数の再代入を行うときに推定した変数のタイプにコンパイルします.
    // Error : type mismach 발생 - 컴파일 오류
    var answer = 123;
    answer = "hello world"

    2.1.4文字列のより簡単なフォーマット:文字列テンプレート

    // 문자열 템플릿 사용
    fun main(args: Array<String>) {
        val name = if(args.size > 0) args[0] else "Kotlin"
        println("Hello, $name!")
    
        if(args.size > 0){
            println("Bye, ${args[0]}")   // args 배열의 원소를 넣기 위해${} 구문 사용
        }
    
        println("\$")  // 달려 표시 ($)를 쓸 경우에는 이스케이프(\) 사용
    
    }
  • コトリンでは、変数を文字列に使用することもできます.→文字列文字が必要な$変数名
  • ハングルと文字テンプレートを使用するときの注意点

  • コトリンはjavaと同様に変数名にもハングルを含めることができます.(すべてのUnicode文字に変数名がある)

  • 文字列テンプレートに$name님, 반가워요のように「$変数名」とハングルを付けると、コンパイルエラーが発生します.これは、コートリンコンパイラが英語と韓国語を識別子として同時に使用しているためです.
    ${name}님, 반가워요変数名を{}で包み、普段は牛で包むのが可読性に良い.
  • 2.2クラスとproperty

    // Java Person 클래스
    public class Person {
        private final String name;
        
        public String getName() {
            return name;
        }
    
        public Person(String name) {
            this.name = name;
        }
    }
    Javaの場合、フィールドが長いほど、コンストラクション関数のパラメータ数が多くなります.つまり,増加を繰り返すコードが増える.
    // 코틀린으로 변환한 Person 클래스
    class Person (val name : String)
  • コトリンのアクセス制御者は基本的に公衆である.そのため省略できます.
  • 2.2.1契約


    Javaは、フィールドとアクセス者を一緒に置くことをPropertyと呼びます.コトリンプロトコルはJavaのフィールドとアクセス者メソッドに完全に取って代わった.
    class Person(
        val name: String,   // private 변수, 읽기 전용, 단순한 공개 getter만 만들어낸다.
        var isMarried: Boolean  // private 변수, 공개 getter, 공개 setter 만들어낸다.
    )
    
    val person = Person("Bob", true)  // new 키워드 사용 안하고 생성자 호출
    // 프로퍼티 이름을 직접 사용해도 코틀린이 자동으로 getter 호출
    println(person.name)
    println(person.isMarried)

    2.2.2カスタム訪問者

    class Rectangle(val height: Int, val width: Int) {
        val isSquare: Boolean
            get() {
                return height == width
            }
    			// get() = height == width
    }
    isSquare Propertyは自己実現を提供するgetterを有する
    クライアントがpropertyにアクセスすると、get()に対応する論理を使用してproperty値が毎回再計算されます.
    パラメータのない関数を定義する方法と、Customgetterを定義する方法は、実装とパフォーマンスに違いはありません.

    2.2.3スペルミスソース構造:ディレクトリとパッケージ


    すべてのスペルミスファイルの一番前にpackage文を置くことができます.
    同じパッケージに属している場合は、他のファイルで定義された宣言として直接使用できます.
    逆に、他のパッケージで定義した宣言を使用するには、import宣言を使用します.
    // 클래스와 함수 선언을 패키지에 넣기
    package geometry.shapes
    
    import java.util.*
    
    class Rectangle(val height: Int, val width: Int) {
        val isSquare: Boolean
            get() = height == width
    }
    
    fun createRandomRectangle(): Rectangle {
        val random = Random()
        return Rectangle(random.nextInt(), random.nextInt())
    }
    // 다른 패키지에 있는 함수 임포트하기
    package geometry.shapes.createRandomRectangle
    
    fun main(args: Array<String>) {
    	println(createRandomRectangle().isSquare)
    }
    Javaと同様に、パッケージごとにディレクトリを整理することが望ましい.特にjavaとcortlinを同時に使用するプロジェクトではjava方式に従うことが重要である.

    2.3式と処理の選択:enumとwhen


    2.3.1クラス定義

    // 간단한 enum 클래스
    enum class Color {
        RED, ORANGE, YELLOW, GREEN, INDIGO, VIOLET
    }
    Java宣言はenum、コートリン宣言はenum class
    // 프로퍼티와 메소드가 있는 enum 클래스
    
    enum class Color(val r: Int, val g: Int, val b: Int)   // 상수 프로퍼티 정의
    {  
    
        RED(255, 0, 0),
        ORANGE(255, 165, 0),
        YELLOW(255, 255, 0),
        GREEN(0, 255, 0),
        BLUE(0, 0, 255),
        INDIGO(75, 0, 130),
        VIOLET(238, 130, 238);    // 반드시 세미콜론으로 종료
    
        fun rgb() = (r * 256 + g) * 256 + b  // enum 클래스 안에 메소드 정의
    }
    
    fun main() {
        println(Color.BLUE.rgb())
    }

    2.3.2 whenを使用してenumクラスを処理する

    fun getMnemonic(color: Color) =
     when (color) {   // 함수 반환 값으로 when 식을 사용
        Color.RED -> "Rechard"
        Color.ORANGE -> "Of"
        Color.YELLOW -> "York"
        Color.GREEN -> "Grave"
        Color.BLUE -> "Battle"
        Color.INDIGO -> "In"
        Color.VIOLET -> "Vain"
    }
    
    fun getWarmth(color: Color) = when (color) {
        Color.RED, Color.ORANGE, Color.YELLOW -> "warm"
        Color.GREEN -> "neutral"
        Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold"
    }
    
    fun main() {
        println(getMnemonic(Color.BLUE))
        println(getWarmth(Color.ORANGE))
    }
    Javaと異なり、四半期ごとの末尾にブレークポイントを入れる必要はありません.
    1四半期に複数の値を組み合わせモードとして使用する場合は、カンマ(,)で区切ります.
    enum定数値をインポートすることで、enumクラス修飾子なしでenumを使用できます.
    import ch2.Color.*
    
    fun getMnemonic(color: Color) = when (color) {
        RED -> "Rechard"
        ORANGE -> "Of"
        YELLOW -> "York"
        GREEN -> "Grave"
        BLUE -> "Battle"
        INDIGO -> "In"
        VIOLET -> "Vain"
    }

    2.3.3 whenを任意のオブジェクトと一緒に使用する


    Javaのswtichとは異なり、コトリンwhenの分岐条件は任意のオブジェクトを許可する.
    fun mix(c1: Color, c2: Color) =
        // when 식의 인자로 아무 객체나 사용 가능, when은 받은 인자 객체가 각 분기 조건에 있는 객체와 같은지 테스트
        when (setOf(c1, c2)) {
            setOf(RED, YELLOW) -> ORANGE
            setOf(YELLOW, BLUE) -> GREEN
            setOf(BLUE, VIOLET) -> INDIGO
            // 매치되는 분기 조건이 없으면 이 문장 실행
            else -> throw Exception("Dirty color")
        }
  • setOf関数とは?パラメータとして渡される複数のオブジェクトを、これらのオブジェクトの集合を含む集合の関数として作成します.集合は要素の集合であり、各要素の順序は重要ではありません.
  • 2.3.4使用時パラメータなし


    ある時点でパラメータがない場合は、各ブランチの条件が達成した結果を計算する必要があります.
    fun mixOptimized(c1: Color, c2: Color) =
        // when 에 아무 인자가 없다.
        when {
            (c1 == RED && c2 == YELLOW) ||
                    (c1 == YELLOW && c2 == RED) -> ORANGE
            (c1 == YELLOW && c2 == BLUE) ||
                    (c1 == BLUE && c2 == YELLOW) -> GREEN
            (c1 == BLUE && c2 == VIOLET) ||
                    (c1 == VIOLET && c2 == BLUE) -> INDIGO
            else -> throw Exception("Dirty color")
        }

    2.3.5インテリジェント鋳造:タイプ検査とタイプ鋳造を組み合わせて

    ( 1 + 2 ) + 4のような算術式を計算する関数を構築しましょう.
    // 식을 위한 인터페이스
    interface Expr
    
    // value라는 프로퍼티만 존재하는 단순한 클래스, Expr 인터페이스를 구현
    class Num(val value: Int) : Expr
    
    // Expr 타입의 객체라면 Sum 연산의 인자가 될 수 있다.
    // 따라서, Num이나 다른 Sum이 Sum의 인자로 올 수 있다.
    class Sum(val left: Expr, val right: Expr) : Expr
    
    // Java 스타일
    // if 사용해서 식 계산
    fun eval(e: Expr): Int {
        if (e is Num) {
            val n = e as Num
            return n.value
        }
        if (e is Sum) {
            // 변수 e 에 대해 스마트 캐스트를 사용한다.
            return eval(e.right) + eval(e.left)
        }
    
        throw IllegalArgumentException("Unkown expression")
    }
    Expr暗黙インタフェース
    Sum,NumクラスはExprインタフェースを実現するクラスであるisを使用して変数タイプをチェックします(Javaのinstanceofと同様).
  • しかしJavaでは変数タイプがinstanceofと決定され、このタイプのメンバーにアクセスするために開発者はタイプ
  • を明示的に選択する必要がある.
  • コトリンで、isで検査を行った後、本当ならコンパイラは自分で選びます.→ Smart Cast
  • インテリジェント鋳物は、isによって変数の値タイプを検査する、その値が変更できない場合にのみ動作
  • を実行する.asキーワード→val n = e as Numを使用した明示的な鋳造

    2.3.6再包装:ifをいつに変更するか


    コトリンのif戻り式→値.価値を創造する.→したがって、Javaとは異なり、他に3つの演算子はありません.
    Javaのifは文→値を返さない.
    // 값을 만들어내는 if 식
    
    fun eval(e: Expr): Int =
        if (e is Num) {
            e.value
        } else if (e is Sum) {
            eval(e.right) + eval(e.left)
        } else {
            throw IllegalArgumentException("Unkown expression")
        }
    // if 중첩 대신 when 사용하기
    fun eval(e: Expr): Int =
        when (e) {
            is Num -> e.value  // 인자 타입을 검사하는 when 분기에서 스마트 캐스트 됨
            is Sum -> eval(e.left) + eval(e.right)
            else -> throw IllegalArgumentException("Unkown expression")
        }

    2.3.7 ifブランチとwhenブランチでのブロックの使用


    ifまたはwhenは、ブランチでブロック→ブロックの最後の文を有効にすると、ブロック全体の結果になります.
    fun evalWithLogging(e: Expr): Int =
        when (e) {
            is Num -> {
                println("num: ${e.value}")
                e.value   // 블록의 마지막 식이므로 e.value가 반환된다.
            }
            is Sum -> {
                val left = evalWithLogging(e.left)
                val right = evalWithLogging(e.right)
                println("sum: $left + $right")
                left + right
            }
            else -> throw IllegalArgumentException("Unkown expression")
        }

    2.4ターゲット・イテレーション:whileとfor rough


    2.4.1同時循環

    // 조건이 참인 동안 본문 반복 실행
    while(조건) {
    	/*....*/
    }
    
    // 맨 처음 무조건 본문 한번 실행 후, 조건이 참인 동안 본문 반복 실행
    do{
    	/*....*/
    } while(조건)

    2.4.2カウントのイテレーション:範囲とカウント


    コトリンにはjava forループに対応する要素はありません.
    val oneToTen = 1..10 // 양 끝 구간 포함, 1 ~ 10
    fun fizzbuxx(i: Int) =
        when {
            i % 15 == 0 -> "FizzBuzz "
            i % 3 == 0 -> "Fizz "
            i % 5 == 0 -> "Buzz "
            else -> "$i "
        }
    
    for (i in 1..100) {
            println(fizzbuxx(i))
        }
    
        for (i in 100 downTo 1 step 2){
            print(fizzbuxx(i))
        }
    step:増分downTo:反転..:常に範囲の末尾を含むuntil:終了値を含まない→for(x in 0 until size)またはfor (x in 0 .. size-1)

    2.4.3マッピングされたイテレーション

    // A ~ F 까지 문자 범위 이터레이션
    for(c in 'A'..'F'){
        // 아스키 코드를 2진 표현으로 변경
        val binary = Integer.toBinaryString(c.toInt())
        // c를 키로 c의 2진 표현을 맵에 넣는다.
        binaryReps[c] = binary  // 자바의 map put 과 유사: binaryReps.put(c, binary)
    }
    
    // 맵에 대한 이터레이션, 맵의 Key와 Value를 두 변수에 대입
    for((letter, binary) in binaryReps) {
        println("$letter = $binary")
    }
    val list = arrayListOf("10", "11", "1001")
    
    // 인덱스와 함께 컬렉션을 이터레이션 한다.
    for ((idx, element) in list.withIndex()){
        println("$idx: $element")
    }

    2.4.4 inローカルセットまたは範囲内の要素をチェックする


    in演算子:範囲に属する値を決定する
    !in演算子:範囲外の値を決定する
    fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'
    fun isNotDigit(c: Char) = c !in '0'..'9'
    
    println(isLetter('q'))      // true
    println(isNotDigit('x'))    // true
    
    fun recognize(c: Char) = when (c) {
        in '0'..'9' -> "It's a digit!"
        in 'a'..'z', in 'A'..'Z' -> "It's a letter!"
        else -> "I don't know"
    }
    
    println(recognize('8'))     // It's a digit!
    比較可能クラス(java.lang.Compabiledインタフェースを実装するクラス)の場合、クラスのインスタンスオブジェクトを使用して範囲を作成できます.

    2.5エラー処理異常


    コトリンのデフォルトの例外処理構文はJavaに似ています
    例外インスタンスを作成するときにnewキーを追加する必要はありません.
    Javaとは異なり、コトリンのthrowは式であり、異なる方法で含むことができる.
    val percentage =
        if (number in 0..100)
            number
        else
    				// throw는 식이다. -> 값을 만들어낸다.
            throw IllegalArgumentException("A percentage value must be between 0 and 100: $number")

    2.5.1 try, catch, finally

    fun readNumber(reader: BufferedReader): Int? {
        try {
            val line = reader.readLine()
            return Integer.parseInt(line)
        } catch (e: NumberFormatException) {
            return null
        } finally {
            reader.close()
        }
    }
    Javaコードとの最大の違いはthrowsセクションにコードがないことです
  • Javaでは、関数を記述する際に、関数宣言後にthrows IOExceptionを付ける必要があります.→IOExceptionはChecked ExceptionなのでJavaはChecked Exceptionを明示的に扱う必要があります.→ある関数が投げ出す可能性のある異常またはその関数が呼び出す他の関数が現れる可能性のあるすべての異常をcatchとして処理する必要があります.未処理の異常はthrowsセクションで明確に指摘されています.
  • コトリンも他の最新のJVM言語のようにChecked ExceptionとUnChecked Exceptionを区別していない.(JavaはChecked Exception処理を強制的に実行する.)

    2.5.2. tryで使用


    コトリンのtryキーワードは式です.→値切る.
    したがって、tryの値を変数に代入することができます.tryはifとは異なり、カッコ{}で囲まなければなりません.
    fun readNumber(reader: BufferedReader) {
    		// 예외가 발생하지 않으면, 이 값을 사용
        val number = try {
            Integer.parseInt(reader.readLine())
        } catch (e: NumberFormatException) {
            // return //catch 블록 다음 코드는 실행 되지 않음
            null      // 예외가 발생하면 null값을 사용
        }
        println(number)
    }
    出典:(書籍)Kotlin Action DemitrizeMerof, ストラナイサコワ 作者の紹介