年: 2020年

エクステンション(拡張) : kotlin

※以下のコードは全て"Target platform: JVMRunning on kotlin v. 1.4.20"のもの。元ページと同じように表記させるのが面倒なのでここで表記するw

※いつも通りの原文無視がちの超訳が多くなった。なんか原文の表現がわかりにくいので適当に超訳したが、勘違いしてる部分も多々あると思う(ノ∀`)

※修飾子(qualifier)の言葉の使い方がちょっと理解出来ない。「オブジェクト.メソッド()」という時にオブジェクトをメソッド()の修飾子と呼ぶのだろうか? 修飾語句でもなんか変だし。加えて言うとmodifierとの違いは何だろうか?


Extensions

Kotlinはクラス継承やDecoratorなどのデザインパターンを使用することなく、新しい機能によってクラスを拡張する能力を提供します。これはエクステンション(拡張/拡張機能)と呼ばれる特別な宣言を介して行われます。

たとえば、内容を変更することができないサードパーティのライブラリのクラスに対して新しい関数を記述できます。このような関数は元のクラスのメソッドであるかのように通常の方法で呼び出すことができます。

このメカニズムは拡張関数と呼ばれます。既存のクラスに対して新しいプロパティを定義できる拡張プロパティもあります。

拡張関数

拡張関数を宣言するには、レシーバ(追加を受ける、つまり拡張したい対象)の型名の後ろに追加する関数名と処理を記述します。以下はMutableListにswap関数を追加する例です。: swap 交換する

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this'は追加先のMutableListを指します。
    this[index1] = this[index2]
    this[index2] = tmp
}

拡張関数内のthisキーワードは、レシーバオブジェクト(ドットの前に記述された型のオブジェクト)を指します。以下のように記述することで任意のMutableListで定義した関数を呼び出すことができます。:

val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // swap()内の'this'は 'list'の値を保持します.

もちろん、この関数はどのMutableListにも意味があり、ジェネリクスにすることができます。:

fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this'はそのlistを指します。
    this[index1] = this[index2]
    this[index2] = tmp
}

レシーバ型の式で使用できるように、関数名の前にジェネリクスの型パラメーターを宣言します。詳細はジェネリクス関数を参照してください。
※この場合、レシーバ型名の前じゃないか? 関数名はあくまでもswapではなかろうか?


拡張機能は静的に解決されます

※なんか難しかったんで、俺氏超訳発動(`・ω・´)シェルダン

拡張機能は拡張するクラスを実際には変更しません。拡張機能を定義することによりクラスに新しいメンバ関数を挿入するのではなく、単に定義した関数をこの型の変数においてドット記法で呼び出しできるようにするだけです。
拡張機能は静的に割当てられます、つまり、レシーバ型の仮想の存在ではないということを強く認識してください。これは呼び出される拡張関数が、実行時にその式を評価した結果の型ではなく、関数を呼び出す式の型によって決定されることを意味します。例えば:

open class Shape
​
class Rectangle: Shape()
​
fun Shape.getName() = "Shape" //※Shapeへ拡張関数 getName()を追加
​
fun Rectangle.getName() = "Rectangle" //※Rectangleへ拡張関数 getName()を追加
​
fun printClassName(s: Shape) {
    println(s.getName())
}    
​
printClassName(Rectangle()) 

このコード例では"Shape"と出力されます。なぜなら呼び出される拡張関数は引数sの宣言型(Shapeクラス)にのみ依存するからです。

クラスにメンバ関数があり、同じレシーバ型と関数名を持ち、指定された引数に適用できる拡張関数が定義されている場合、メンバが常に勝ちます。例えば:

class Example {
    fun printFunctionType() { println("Class method") }
}
​
fun Example.printFunctionType() { println("Extension function") }
​
Example().printFunctionType()

このコードは"Class method"を出力します。
※"拡張関数と同じシグニチャ(関数名と引数)を持つメンバ関数がレシーバ型にある場合、常にメンバ関数が呼ばれます。"とか"レシーバ型内で拡張関数と既存のメンバ関数のシグニチャが競合する場合、常にメンバ関数が呼ばれます"という表現じゃ駄目なんだろうか?
Javaのバイトコードにした時に第一引数としてレシーバのオブジェクトを取るらしく、故にkotlin上では同じシグニチャに見えるけれども、実行時のJavaコードでは違うシグニチャになるから同一シグニチャという表現を避けたのかな?
#Kotlin の拡張関数の優先度についてメモ

ただし、拡張関数が同じ名前でシグニチャが異なるメンバ関数をオーバーロードしてもまったく問題ありません。:

class Example {
    fun printFunctionType() { println("Class method") }
}

fun Example.printFunctionType(i: Int) { println("Extension function") }

Example().printFunctionType(1)
​

※そもそもシグニチャは関数名も含むはずだから、この文章が何を言いたいのかよくわからない(´・ω・`) "同じ関数名でも引数の数や型が異なる、即ちシグニチャが異なるメンバ関数"という表現の方が妥当なような気がするけど、それでもここでわざわざ言っている意味がわからない。 メンバ関数と同じシグニチャの拡張関数を作成する、即ちオーバーライド的なことをするとメンバ関数が勝つということの対比としてオーバーロードに言及したかったのか?


Null許容レシーバ

拡張機能はnull許容のレシーバ型でも定義できることに注意してください。この場合の拡張関数は、値がnullであるオブジェクト変数であっても呼び出すことができ、本体内で"this == null"を判定できます。この仕組みにより、Kotlinではnull判定をせずにtoString()を呼び出すことができます。:チェックは拡張関数内で行われます。

fun Any?.toString(): String {
    if (this == null) return "null"
    // null判定後、'this'はスマートキャストにより非null型に変換されるので、
    // 以下のtoString()はAnyクラスのメンバ関数のtoString()になります。
    return toString()
}

拡張プロパティ

拡張関数と同様に、Kotlinは拡張プロパティも提供しています。

val <T> List<T>.lastIndex: Int
    get() = size - 1

拡張機能は実際にはメンバ(変数)をクラスに挿入しないため、拡張プロパティにバッキングフィールドを持たせる有効な方法がないことに注意してください。これが拡張プロパティに初期化子(イニシャライザ)が許可されていない理由です。拡張プロパティの動作はゲッター/セッターを明示的に提供することによってのみ定義できます。

例:

val House.number = 1 // エラー:初期化子は拡張プロパティには許可されていません。

※なんでここにエラー例だけしか載せてないんだろうか?


コンパニオンオブジェクト拡張

クラスにコンパニオンオブジェクトが定義されている場合、そのコンパニオンオブジェクトの拡張関数と拡張プロパティを定義することもできます。

コンパニオンオブジェクトの通常のメンバと同じ様に、修飾子としてクラス名のみを使用して呼び出すことができます。: ※クラス名とかって修飾子に分類されるの?

class MyClass {
    companion object { }  // 「コンパニオン」と呼ばれます。
}
​
fun MyClass.Companion.printCompanion() { println("companion") }
​
fun main() {
    MyClass.printCompanion()
}

拡張機能の範囲

ほとんどの場合、拡張機能はトップレベル(パッケージの直下)で定義します。:

package org.example.declarations
 
fun List<String>.getLongestString() { /*...*/}

定義を行ったパッケージの外部でその拡張機能を使用するには、呼び出し側でインポートする必要があります。:
call siteってあるけど、ピンポイントではなく、そのパッケージでインポートをするんだから呼び出し側(side)とかの方が適切ではなかろうか?

package org.example.usage
​
import org.example.declarations.getLongestString
​
fun main() {
    val list = listOf("red", "green", "blue")
    list.getLongestString()
}

詳細については、インポートを参照してください。


拡張関数をメンバとして宣言する

クラス内部で、別のクラスの拡張を宣言できます。このような拡張の内部には複数の暗黙的なレシーバがあります。(これらのオブジェクトのメンバには、修飾子なしでアクセスできます。) 拡張が宣言されているクラスのインスタンスはディスパッチレシーバと呼ばれ、拡張関数のレシーバ型のインスタンスは拡張レシーバと呼ばれます。
※ここのmultipleの意味がよくわからない。暗黙的なレシーバオブジェクトが存在するのは良いとしても。

class Host(val hostname: String) {
    fun printHostname() { print(hostname) }
}
​
class Connection(val host: Host, val port: Int) {
     fun printPort() { print(port) }
​
     fun Host.printConnectionString() {
         printHostname()   // Host.printHostname()を呼ぶ。
         print(":")
         printPort()   // Connection.printPort()を呼ぶ。
     }
​
     fun connect() {
         /*...*/
         host.printConnectionString()   // 拡張関数 printConnectionString()を呼ぶ。
     }
}
​
fun main() {
    Connection(Host("kotl.in"), 443).connect()   //"kotl.in:443"と出力される。
    //Host("kotl.in").printConnectionString(443)  //Connectionの外側で拡張関数 printConnectionString()は利用出来ないので、この呼出はエラーになる。
 
}

ディスパッチレシーバと拡張レシーバのメンバ間で名前が競合する場合は、拡張レシーバが優先されます。ディスパッチレシーバのメンバーを参照するには、this修飾構文を使用できます。

class Connection {
    fun Host.getConnectionString() {
        toString()         // Host.toString()を呼ぶ
        this@Connection.toString()  // Connection.toString()を呼ぶ
    }
}

メンバとして宣言される拡張関数は、openとして宣言でき、サブクラスでオーバーライドすることができます。つまり、このような関数の割当は、ディスパッチレシーバ型に対しては仮想ですが、拡張レシーバ型に対しては静的です。

※ここもopenとして宣言できると表現するよりも素直に"メンバ関数と同様にopenを用いることによってサブクラスでオーバーライドすることができます。"とかの方が良いような。

open class Base { }
​
class Derived : Base() { }
​
open class BaseCaller {
    open fun Base.printFunctionInfo() {
        println("Base extension function in BaseCaller")
    }
​
    open fun Derived.printFunctionInfo() {
        println("Derived extension function in BaseCaller")
    }
​
    fun call(b: Base) {
        b.printFunctionInfo()   // call the extension function
    }
}
​
class DerivedCaller: BaseCaller() {
    override fun Base.printFunctionInfo() {
        println("Base extension function in DerivedCaller")
    }
​
    override fun Derived.printFunctionInfo() {
        println("Derived extension function in DerivedCaller")
    }
}
​
fun main() {
    BaseCaller().call(Base())   // "Base extension function in BaseCaller"
    DerivedCaller().call(Base())  // "Base extension function in DerivedCaller" - dispatch receiver is resolved virtually
    DerivedCaller().call(Derived())  // "Base extension function in DerivedCaller" - extension receiver is resolved statically
}

可視性に関する注意

拡張機能は、同じスコープで宣言された通常の関数と同じように、他のエンティティの可視性を利用します。例えば:

-ファイルのトップレベルで宣言された拡張機能は、同じファイル内の他のprivateトップレベル宣言にアクセスできます。 :

-拡張機能がそのレシーバ型の外部で宣言されている場合、そのような拡張機能はレシーバのprivateメンバにアクセスできません。

無料配信漫画等々をいろいろ読んだ(・∀・)-68

SEIZAN 1巻 ヨゼフ峯アツシ

江戸時代後期....原因不明の大天災【天異地変】が起こった!本来は混じり合わぬはずの天界・霊界・魔界が地上に混在する事態と成って三十数年!!!!!不死の山....富士山の頂上に突如として現れた天界の住居【神界】の下には人々が暮らすには余りにも苦難が多い魔界が広がり闇の存在....すなわち魔人・魔物に蹂躙される生き地獄があった!!!!しかし....そこに現れた光の侍【神人】の強大な神霊力....龍皇の霊威が闇を照らす!!!!神人として生きながら人としての情けで神の技【神形刀流】を使う神人は....その名を清斬!!!!闇を祓い世に光を取り戻す素浪人が来る!!!!

6円で購入。
作者は長崎の松浦静山を主人公にした『予の話』を描いたヨゼフ峯アツシ。

主人公の名前は字は清斬であるが、読みはSEIZANなので、やっぱり松浦静山から来ているんだろうな。

アシスタントを使わない為か、背景に時間をかけない為か、或いはCGを活用した漫画を描きたかったのか、CGと漫画が融合というか重ね合わせられた感じになっている。

話自体はうーん…つまらないとまでは言わないけども、今ひとつ合わなかった。

あと、吹き出しが多かったり、フォントが微妙だったり、人間キャラの表情の変化が乏しかったところもちょっと(´・ω・`)

結局、九頭竜と戦わずに終わったのか…


国際ビジネスウォーズ 無国籍企業橘商会 里見桂 / 吉村作治

舞台は1991年、湾岸戦争の爪痕がまだ真新しい中近東。
“無国籍企業”とあだ名される名うての商社橘商会に勤める金子洋平は、カイロ支店への転勤を命じられる。
次期社長候補と目される支店長の大曲太一に出迎えられた金子は、大曲に連れられ秩序のない混沌とした商戦(ビジネスウォーズ)の最前線に身を投じていく。
中東情勢に精通する考古学者教授の吉村作治が原作を手がける、異色のビジネスコミックが電子書籍でついに復刊!

6円で購入。
これまたつまらなくはなかったけども、あんまりビジネス云々の凄さとか爽快さはなかったような気がする。
吉村作治原作だったからかw

せやで、金子(・∀・)


将国のアルタイル嵬伝/嶌国のスバル(1)カトウチカ / 小林裕和 / カトウコトノ (監修)

「将国のアルタイル」のアナザーサイド、嵬伝<がいでん>開幕! 大陸の強国に蹂躙された、極東の島国・日薙<くさなぎ>。奴隷として虐げられる日薙人のもとに、滅びた皇家の遺子、皇子<みこ>が帰還。彼らは遂に反撃の火蓋を切る――! 「将国」世界を震撼させた新兵器“東弓”を巡る、知略と蛮勇入り乱れた“国土回復譚”が今、始まる!

「『将国のアルタイル』が売れたから、あれだろ、ヒット漫画が生まれたらすぐスピンオフして小銭集めようとする、いつものこきたない手法だろ( ゜σ・゚)ホジホジ」
と思って長い間放置していたが、読んでみたらすごくおもしろかったです(・∀・)(小並感)

モデルは日本と中国(元(?))みたいな感じではあるが、そういうのは抜きで、小勢力が大勢力を徐々に切り崩していく展開はやはり盛り上がる(`・ω・´)

ちなみに嶌(嶋)とう・しまと読み間違えていたのは内緒だ(*´・ω・)

皇子の正体とか続きが気になるわ(・∀・)


必殺仕置長屋 1 木村知夫 / 山田誠二 / ABC・松竹

中村主水の親戚で冴えない八丁堀同心、鈴木主膳。昼行灯で、お人好し。母親に頭が上がらない主膳だが彼には、人には言えぬ裏の顔があった。
法で裁けぬ悪党どもを闇で裁いて仕置する─許せぬ悪の始末を金で請け負う闇の仕事師たちの活躍を描いた傑作テレビ時代劇「必殺」シリーズのコミックが電子書籍となって復活!
電子書籍版限定!!当時のエピソードを綴った木村知夫肉筆のあとがき付き!!

『花魁夜叉』や『武頼漢』と同じ作者。

んー、つまらなくはないけども、んー(´・ω・`)
なんだろうね、ページ数の絡みで全てのキャラを有効に動かせてないという感じ?
ページ数というよりも大ゴマを使いすぎなんじゃなかろうかという気もしないこともないw

皆、賞金稼ぎっていう設定で仕置長屋ってところに集めてしまっているのもいけないのかもなぁ…
大道芸とかで稼ぐ時もいつも一緒に行動してる感じだし。

amazonのレビューでも言及されていたが…


女子中学生エクソシスト祓 木村知夫 / 小津夕喜

あの不良漫画の金字塔「Let’sダチ公」痛快時代劇漫画「必殺仕置長屋」などの作画である木村知夫が、新鋭原作者の小津夕喜(デビュー作)とタッグを組んだ痛快オカルティックヒロイン作品。
主人公、女子中学生の祓(はらい)はなんと!悪魔払いの大先生。ある日、地下室で目撃した「変な物」に出会ってからの祓の運命が動き始める…。2014年から1年間商業誌連載。未単行本化作品がついに電子化!電書バト限定、当時のエピソードを綴った木村知夫肉筆のあとがき付き。

6円で購入。
これまた作者は木村知夫。
なんとなくノリが『ラブZ』に似ているノリがあったので古い作品なのかなと思いきや、2014年くらいの作品らしい。

今はもう休刊してしまった、小池一夫が編集長の『ストレンジャーソレント』に連載していた模様。

つまらないと言うほどでもなかったかなぁ…くらい。
絵柄も展開もやや独特であったけどもw
新キャラが出て来たところで小池一夫の判断で打ち切られたみたい。

こっちでも"触手"になっとる(´・ω・`)


みどりのマキバオー つの丸

まあまあ面白かったかな(・∀・)
チュウ兵衛とカスケードが良いキャラだった。

競馬の馬が主役だと展開が一年ごとのレースの繰り返しになっちゃうからか、ドバイWCみたいな話にしたんだろうか?
もうあの段階で終わりは決まっていたのかな?

でも正直、ドバイWCはベアナックルなしでは話が持たなかったなw
まさかあそこまで重要な存在になるとは思わなかったw

最終回はあれはあれで良かったのかなって感じ。

続編の『たいようのマキバオー』を読もうかなと思ったが、今作のマキバオー、つまりはうんこたれ蔵は出て来ず、マキバコの産駒 ヒノデマキバオーが主人公ということを知り、読むのは止めた(ノ∀`)

一応、一話だけは目を通したけど、長そうだし、読んでる漫画も多いので回避した(・∀・)


エアマスター 柴田ヨクサル

十年かそこら前辺りに一度最後まで読んだような気がしたが、また読みたくなったので読んだ。
正直、絵が結構雑だし、話も結構アレな部分もあるんだけど、なんか読んでて熱くなれるところもあったりするので好き(・∀・)

崎山香織が好きなんだけども、格闘パワー不足というか強さのインフレ展開の為にサンパギータ・カイにリプレースされてしまったような感じになって少し悲しかった(´・ω・`)
一緒に蓮華もみおりにリプレースされてしまったような気もしないでもない。
いつか月雄とくっついたりするんだろうかw
坂本ジュリエッタも意外と嫌いではないw
長戸は嫌だけどw

wikipediaをちらっと見たら作者はカイが一番好きらしいw
( ´・ω・)エ?
『ハチワンダイバー』に『エアマスター』のキャラ出てくんの?
そう言えば『谷仮面』の谷も何か出てくるんだっけか…
まああんまりwikipediaを読んでネタバレを喰らうのは避けようw

全28巻と長かった為、ゼブラックで一日一話、マンガParkで午前午後のポイントによる2話+CMを観て3話の計6話を読みつつ、ゲーム等で入手したポイントで何とか読み切ったわ…(ヽ'ω`)

『マフィアシティ』で入手したポイントでは全然足らず、『放置少女』(LV40 950BC)と『KOF'98 UM OL』(10連ガチャ2回 792BC)も全部使い果たしてなんとかなった…_| ̄|○

さながら渺茫にラストバトルを挑む深道がごとき総力戦でしたわ(・∀・)

まあしかしながらにして思ったのは、こういう一日一話とかの電子書籍サイトでは中々実装出来ないだろうけど、ポイントを一遍に払った時とかは各話の細切れ状態をなくして、せめて一話単位で読めるようにして欲しいわ(´・ω・`)

いちいち広告とか他の漫画の紹介とかって没入感を著しく阻害するから。
本当に漫画の読者を楽しませたいのであれば、そういったUIの融通が効くようにして欲しいところではある。

少なからず、或る漫画を連続して読んでる最中の他の漫画の紹介って嫌がらせにしかならないと思った(´・ω・`)


『放置少女』

ゲームとして面白いかどうかは何とも言えないけれども、まあ楽にポイントはもらえた(・∀・)

ちょろっとだけ攻略ページを眺めて武将で開始、ボス挑戦を出来るだけ進めて、後はちょこちょこ強化等をして放置。何時間置きにちょこちょこ強化等をする感じ。

Lv20到達は7時間弱くらいで、LV40到達は3日と数時間だった。
おそらくこの手のゲームの勘所が分かっている人ならば、もっと早く到達出来ると思う。

『エアマスター』を読了したので、もうポイントは必要ないのだが、もう少し続ける。
40日の期間内に無課金でLV80って本当に行けるのかどうかを試したいだけなんだけどもw
LV60はどうにかなりそうではある。6日間でLV50に行ってるので。


『THE KING OF FIGHTERS '98ULTIMATE MATCH Online』

リズム系というかタイミング系ミニゲームを集めた感じ?
KOFシリーズが好きな人なら楽しめるんじゃないかなぁ?

俺氏は全然得意でもないし、それほど好きというわけでもないが、KOFシリーズはそれなりに知っているので、まあキャラゲーとしてなんとなくまだポチポチしてる。

こちらは即日3時間ちょっとで10連ガチャを2回を達成出来たけど、それ以降は「初めてガチャで直接にLR格闘家n体を入手する」とかなので達成出来そうにないw

この条件文が何を意味してるのかもよくわからないw
"初めてガチャ"というものがあるのか「初めて、ガチャで」なのか?
「直接に」っていうのも変な気がする。

まあこっちも適当に飽きるまでやる感じで(・∀・)

シールクラス(密閉クラス) : kotlin

シールクラス(密閉クラス)

シールクラスは限定的なクラス階層を表すために使用されます。
このクラスでは値は限定されたセットの型の1つを持つことができますが、それ以外の型を持つことが出来ません。

ある意味で、これらは列挙型クラスの拡張です。:
列挙型の値のセットも制限されますが、各列挙型定数は単一のインスタンスとしてのみ存在するのに対し、シールクラスのサブクラスは、状態を含むことができる複数のインスタンスを持てます。

シールクラスを宣言するには、クラス名の前にsealed修飾子を加えます。シールクラスはサブクラスを持つことができますが、それらはすべてシールクラス自体と同じファイルで宣言する必要があります。 (Kotlin 1.1より前は、ルールはさらに厳格でした。クラスは、シールクラスの宣言内にネストする必要がありました)。

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

(上記の例では、Kotlin 1.1で追加された新機能を利用しています。
データクラスがシールクラスを含む他のクラスを継承出来るようになりました。)

シールクラス自体は抽象クラスであり、直接インスタンス化は出来ず、抽象メンバを持てません。

シールクラスは、privateではないコンストラクタを持つことはできません。(それらのコンストラクタはデフォルトでprivateです)。

シールクラスのサブクラスを継承するクラス(間接継承)は、必ずしも同じファイル内ではなく、どこにでも配置できることに注意してください。

シールクラスを使用する主な利点は、when式で使用するときに役立ちます。ステートメントがすべてのケースをカバーしていることを確認できる場合は、ステートメントにelse句を追加する必要はありません。ただし、これはwhenをステートメントとしてではなく、式として使用(し、その結果を使用)する場合にのみ機能します。

fun eval(expr: Expr): Double = when(expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
    // 全てのケースをカバーしている為、`else`句は必要ありません。
}

型判定とキャスト : kotlin

型判定とキャスト

is演算子と!演算子による型判定

※これis演算子と否定の!演算子の組み合わせだから、こういう表現の方が正しいような気がするけれども、どうだろうか(´・ω・`)?

is演算子またはその否定形式である!isを使用して、実行時にオブジェクトが特定の型に準拠しているかどうかを確認できます:

if (obj is String) {
  print(obj.length)
}

if (obj !is String) { // !(obj is String)と同じです。
  print("Not a String")
}
else {
  print(obj.length)
}

スマートキャスト

Kotlinでは多くの場合、キャスト演算子を明示的に使用する必要はありません。コンパイラは不変の値に対するis演算子の使用を探知し、必要に応じて(安全な)キャストを自動的に挿入するからです:

fun demo(x: Any) {
  if (x is String) {
    print(x.length) // xは自動的にStringにキャストされます。
  }
}

コンパイラは、否定判定の結果がReturnになる場合にキャストが安全になること(キャストが発生しないこと?)を理解するほどに賢いです: ←※いろんな翻訳サイトを使ってもいまいち翻訳しきれなかったのでちょっと超訳(´・ω・`)シドニィ

if (x !is String) return
  print(x.length) // xは自動的にStringにキャストされます。

また&&および||演算子の右側でも:

  // `||`の右側でxは自動的に文字列にキャストされます。…(1)(2)
  if (x !is String || x.length == 0) return

  // `&&`の右側でxは自動的に文字列にキャストされます。…(2)
  // 同上
  if (x is String && x.length > 0)
      print(x.length) // xは自動的にStringにキャストされます。

(1)原文に即して翻訳したけれども、コンパイラはis判定でtrue(または!is判定でfalse)で、後の行でその変数を使用する場合にのみ即時キャストするのか、使用直前でキャストするのかでここの文言が変わって来るような気がする。そういう意味合いにおいてはいつキャストされるかということを明示した方がいいのではなかろうか?
(2)stringじゃなくてStringだな。ここの二箇所だけstringになってる。どうでもいいけどw

このようなスマートキャストは、when式とwhileループでも機能します。:

when (x) {
  is Int -> print(x + 1)
  is String -> print(x.length + 1)
  is IntArray -> print(x.sum())
}

コンパイラが判定時と実際の使用時の間で変数が不変であることを保証できない場合、スマートキャストは機能しないことに注意してください。より具体的には、スマートキャストは次のルールに従って適用されます。:

valローカル変数 - 常時;
valプロパティ - プロパティがprivateまたはinternalである場合、またはプロパティが宣言されているのと同じモジュールで判定が実行される場合。スマートキャストは、openのついた継承可能なプロパティまたはカスタムゲッターがあるプロパティには適用されません。
varローカル変数 - 変数が判定時と実際の使用時の間で変更されておらず、それを変更するラムダに捕捉されていない場合。
※Kotlinのラムダ式はラムダ式の中から、外側の変数の値を変更することができ、これを捕捉できると表現する模様。まあ詰まるところ変更されない限りということだろうか。https://maku77.github.io/kotlin/basic/lambda.html
varプロパティ- 不可。(このvarプロパティは他のコードによっていつでも変更されうる為。)


"アンセーフ(安全ではない)"キャスト演算子

通常、キャストが不可能な場合、キャスト演算子は例外をスローします。したがって、私たちはそれをアンセーフ(安全ではない)と呼びます。 Kotlinでの安全ではないキャストは、中置演算子 asによって行われます("演算子の優先順位"を参照)。:

val x: String = y as String

この型はnull許容ではないため、nullをStringにキャストできないことに注意してください。つまり、yがnullの場合、上記のコードは例外をスローします。 Javaキャストのセマンティクスに一致させるには、キャストの右側にnull許容型が必要です。
※キャストの右側だけじゃなくて左側の宣言の型にも必要なんじゃ? それとも型の右側という意味?

val x: String? = y as String?

"セーフ(安全な)"(null許容)キャスト演算子

例外がスローされるのを避けるために、失敗時にnullを返すセーフキャスト演算子as?を使用できます。

val x: String? = y as? String

as?の右側が非null型の文字列であることに関わらず、キャストの結果はnull許容型です。