Swift ざっくり文法 (1)
statement
- 区切りは、
;
か改行 ;
付けないことが一般的
- 区切りは、
print
print("blue", "green", separator: "+", terminator: ",") print("yellow", terminator: ",") print("red") // blue+green,yellow,red
print(#file) // MyPlayground.playground print(#line) // 16 print(#column) // 7 print(#function) // __lldb_expr_57
constant, variable
--- --- constant let variable var {}
で区切られている範囲がconstant, variableのスコープ- class
- method
- if statement
let name: String name = "タナカ"
let name: String = "タナカ"
let name = "タナカ"
- 演算子の、前後に空白を入れるか/詰めるかしないとError
price = 2500 * rate // ok price = 2500*rate // ok price = 2500* rate // error: consecutive statements on a line must be separated by ';'
- 型判定
let tax = 0.08 print(type(of:tax)) // Double
- 型変換
let num: Int = 4 // 4 Double(num) // 4.0
- 文字列中の変数展開
let hoge = 32 print("hoge: \(hoge)")
Reference from
SwiftのOptionalまわりについて
- Swiftの変数・定数はnilが発生しないようになっていて、nilを代入したい変数は、型をOptional型にする必要がある。
- String?のように型の後ろに?をつけるとnilを代入できるOptional型にWrapされる
let nums = [3, 4, 6] let lastNum = nums.last let ans = lastNum * 2 // Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?' ? print(ans)
lastNum
に数値ではなくnilが入ってる可能性があり、もしnilだった場合、lastNum * 2
が計算できずバグの要因になる可能性がある。したがって、Swiftはこういう場合、エラーを防ぐため、変数・定数にnilが代入されることを黙っては許可しない。
var num:Int num = 5 num = nil // Nil cannot be assigned to type 'Int'
nilを変数に代入しようとすると上記のようなエラーになる。
- var num:Int + var num:Int? num = 5 - num = nil // Nil cannot be assigned to type 'Int' + num = nil print(num) // nil
OptionalValue とは、nilの可能性がある値のこと。
上記のように、型の後ろに ?
を付けることで、numは、OptionalValue を代入できる Optional型の変数になり、num = nil
の式はエラーではなくなる。
var num:Int? num = 5 print(num) // Optional(5)
var num:Int? num = 5 print(num * 3) // Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?' ?
型に ?
を付けて宣言した変数にはnilを代入できることがわかったが、Optional 型の変数にnil以外の値を代入したときには注意が必要
上記の num
は、Int型の5が、Optional(Int)
のようにWrapされている状態。OptionalValueは、このままでは使えない。
var num:Int? num = 5 - print(num * 3) // Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?' ? + print(num! * 3) // 15
Optional(Int)
を計算式で使うには、Optional()
のラップを取り除く、つまりunwrapする必要がある。
unwrapの最も簡単な方法は、OptionalValue に !
をつけること。
var num:Int? num = nil print(num! * 3) // Fatal error: Unexpectedly found nil while unwrapping an Optional value
ただOptionalValueが本当にnilだった場合、強制unwrapするとエラーになる。
var num:Int? num = nil if num != nil { print(num! * 2) } else { print("num is empty") }
したがって、上記のようにnumがnilでないか確認する必要がある。 それをSwift側でやってくれるのが、Optional Binding。 Optional Binding とは、Optional Valueがnilでなければ値をunwrap して、一時変数に代入し、nilの場合はfalseを返す機能。(if, while, guard-else)
- if
var str:String? str = "Swift" if let msg = str { // Optional Valueがnilでなければ、値をunwrapして一時変数に代入 print(msg + "world") } else { // Optional Valueがnilのときは、else blockが実行される print("hello world") }
- if-where
let year1:String = "2001" let year2:String = "2016" if let startYear = Int(year1), let endYear = Int(year2), startYear < endYear { // year1, year2がnilだった場合、`startYear < endYear` の式は実行されない let years = endYear - startYear print("\(years)年間") // 15年間 }
- dictionary
var sum = 0 let dic:[String:Int?] = ["a": 24, "b": nil, "c": 10, "d": nil] for (_, value) in dic { if let num = value { sum+=num // dicから順に取り出したvalueがnilでないときだけ実行される } } print("数値の合計は\(sum)") // 34
- while
var str:String? = "★" var repeatString:String = "" var i = 0 while let stamp = str { // strがnilじゃないときunwrapしてstampに代入。nilならwhileループを実行しない。 repeatString += stamp i += 1 if(i >= 10) { break } } print(repeatString) // ★★★★★★★★★★
- guard-else
let who = "さくら" var level:Int? func hello() { guard let theLevel = level else { print("level is nil") return } if theLevel<10 { print(who+"隊員") } else { print(who+"上級隊員") } } hello() // level is nil levelがnilなので、処理が中断されている level = 5 hello() // サクラ隊員
print(count) // nil print(count ?? 2) // 2 price = (count ?? 2) * 250 print(price) // 500 count = 3 print(count) // Optional(3) print(count ?? 2) // 3 price = (count ?? 2) * 250 print(price) // 750
OptionalValueがnilのとき、??
を使うとnilに代わる値を指定できる
var balls:[(size:Int, color:String)] =[] - var ballSize = balls.first.size // Value of optional type '(size:Int, color:String)?' not unwrapped; did you mean to use '!' or '?' ? + var ballSize = balls.first?.size print(ballSize) // nil
var balls:[(size:Int, color:String)] =[(size:2, color:"red"), (size:4, color:"green") ] - var ballSize = balls.first.size // Value of optional type '(size:Int, color:String)?' not unwrapped; did you mean to use '!' or '?' ? + var ballSize = balls.first?.size print(ballSize) // Optional(2)
.
でアクセスするときに対象に?
をつけることで実行時エラーを回避できる記述方法をOptional chainと呼ぶ
上記だと、Optional型で、値を使うことができず、unwrapする必要があるので、Optional Bindingと組み合わせる。
var balls:[(size:Int, color:String)] =[(size:2, color:"red"), (size:4, color:"green") ] var ballSize = balls.first?.size + if let ballSize = balls.first?.size { + print(ballSize) // 2 + }
reference from
随時更新!! Xcode shortcutまとめ
Xcode
--- | shortcut |
---|---|
New Project | command + shift + n |
New Playground | option + command + shift + n |
Tool Bar | command + option + t |
Navigation | command + 0 |
Debug Area | shift + command + y |
Utility Area | command + option + 0 |
Modify Indentation | ctrl + i |
Grep File | command + shift + o |
Utility Area の object library の grep | command + option + ctrl + 3 |
Go Back | commad + ctrl + ← |
Show Standard Editor | command + enter |
Show Assistant Editor | command + option + enter |
Simulator
--- | shortcut |
---|---|
Toggle Software keyboard | command + k |
reference from
随時更新!! AWS S3 cli のよく使うコマンドまとめ
s3にあるオブジェクトの総量を見たい時
$ aws s3 ls --summarize --human-readable --recursive s3://<backet name> --- Total Objects: 21887 Total Size: 2.7 GiB
s3にディレクトリを同期
$ aws s3 sync <local path> s3://<s3 backet> --exact-timestamps
reference from
http://www.task-notes.com/entry/20150904/1441335600 https://docs.aws.amazon.com/cli/latest/reference/s3/index.html
随時更新!! やってそうでやってなかったchromeのデバッグ手法
chromeでdebugするときどういう機能を使ってデバックしていますでしょうか?自分は基本、debugger
とconsoleくらいしか使っていません。この記事では、目についたやってなかったchromeのデバッグ手法を随時追記していきます。
条件的breakpoint
source panel で行番号のところを右クリックすると Add conditional breakpoint
というボタンが出てくるので、そのボタンを押すと、表現を記述できる。そうするとその表現がtrueのときにbreakpointが発火される。
reference from
https://javascript.info/debugging-chrome https://developers.google.com/web/tools/chrome-devtools/
知ってそうで知らなかったJavascript
最近いろいろvueとかreactとか触っているときにそもそも自分はJavascriptがわかっているのかと不安になったので、以下のチュートリアルをやってみた。なんとなくわかるけど、明確に言語化できていなかったところをまとめた。
Strict mode
what is strict mode
長い間Javascriptは、互換性の問題が発生することなしに、発展してきた。新しい機能・仕様が言語に追加されても、古い機能は変わらなかった。このメリットは、既存のコードを壊さないことである。だがデメリットとして、過去のJavascriptの開発者のミスが言語にずっと残ってしまうという問題があった。それを解決するのが、strict mode である。
2009年、ES5がリリースされた。そのとき新しい機能の追加や既存のコードの修正が行われた。それ以前のコードを動かすため、デフォルトだとES5リリース時の殆どの改善はオフになっている。したがって、ES5で改善された仕様を有効化するために、use strictを使う必要がある。
'use strict'
num = 5; // the variable "num" is created if didn't exist alert(num); // 5
ok
'use strict' num = 5; // the variable "num" is created if didn't exist alert(num); // 5
エラーになる。
一言
どうせ今の時代( 2018/04 )ES6で書いてコンパイルするから過去のコードを読むために知っておく必要はあるが、use strict
を使うことはないだろうと感じた。どうやら、ES6は最初からstrict modeになっているらしい。
colorOrange or COLOR_ORANGE, 定数の命名におけるcamel caseとsnake caseの違い
snake case
const COLOR_RED = "#F00"; const COLOR_GREEN = "#0F0"; const COLOR_BLUE = "#00F"; const COLOR_ORANGE = "#FF7F00"; let color = COLOR_ORANGE; alert(color); // #FF7F00
camel case
const pageLoadTime = /* time taken by a webpage to load */;
定数ということは値が決して変わらない(再代入されない)ということだ。だが、ものによっては実行まで値がわからないものがある。
したがって、実行前から値がわかっていて今後その値が変わらないものと、実行時に値が決まり今後その値が変わらないもので、COLOR_ORANGE
と colorOrange
で記法を分ける。
`` backtickについて
ES6以前は、文字列内で変数展開ができなかったので、以下のように書くことしかできなかった。
let hoge = "hoge" 'foo' + hoge + 'fuga'
だが、ES6になって、以下のように変数展開できるようになった。
`foo${hoge}fuga`
一言
知ってた。
null とundefinedとNaN
null
何もない、空という意味。"nothing", "empty" or "value unknown"
undefined
値が定義されていない。"value is not assigned"
もし変数が宣言されていて、何も値が代入されていなければ、その変数はundefined
になる。
let x; alert(x); // shows "undefined"
NaN
計算のエラー。
alert( "not a number" / 2 + 5 ); // NaN
typeof
typeof演算子は、引数の型を返す。
typeof null // "object"
nullの型判定でobjectが返るのは、Javascriptの仕様のエラー。
Number(undefined) // NaN Number(null) // 0 Number(true) // 1 Number(false) // 0 Number("hoge") // NaN Number("") // 0
false, null, "" の場合のみ0, trueで1, "hoge", undefined だとNaNになる。
Boolean(0) // false Boolean(null) // false Boolean(undefined) // false Boolean(NaN) // false Boolean("") // false // any other value becomes true
Booleanだと基本空っぽいもの( 0, "", null, undefined, NaN )は、falseになる。ただ、Boolean("0")
とかだと文字列になるからtrueが返る。
null とundefined の、0との比較
nullとundefinedの比較
alert( null == undefined ); // true alert( null === undefined ); // false
何にも型変換しないので
nullと0との比較
alert( null > 0 ); // (1) false alert( null == 0 ); // (2) false alert( null >= 0 ); // (3) true
なぜ(1)(2)がfalseになっているのに、(3)だけtrueになっているのか
理由
==
と、>, <, >=, <=
は動きが違うから。>, <, >=, <=
は、null を数字に変換して0にして比較するけど、==
は型変換しないから。
undefined と0の比較
alert( undefined > 0 ); // false (1) alert( undefined < 0 ); // false (2) alert( undefined == 0 ); // false (3)
(1)と(2)がfalseなのは、undefinedがNaNに変換されるから。
そして、NaNはすべての比較演算子でfalseを返す。
最後にfalseになっているのは、==
でundefinedとイコールになるのはnullだけだから。
文字列と数値の変換
alert( 1 + '2' ); // '12' (string to the right) alert( '1' + 2 ); // '12' (string to the left) alert(2 + 2 + '1' ); // "41" and not "221" alert( 2 - '1' ); // 1 alert( '6' / '2' ); // 3
文字列の足し算をすると片方の値は文字列に変換される。 引き算割り算は数値計算になる。
counter++, と ++counterの違い
- increment/decrement は、変数にのみ使える。したがって、
5++
みたいなのはエラーになる。
let counter = 0; counter++; ++counter; alert( counter ); // 2, the lines above did the same
let counter = 0; alert( ++counter ); // 1
先に1が足される
let counter = 0; alert( counter++ ); // 0
次のループで1が足される。
演算子の優先順位
演算子には優先順位があり、それにしたがって演算される。
a = 1 + 2, 3 + 4, 5 + 6 // a = 3, 7, 11 alert(a) // 11
カンマで複数の式を評価できるが、結果として返るのは、最後の値。
カンマは、=
より順位が低い。
比較演算子
alert('a' > 'A'); // true alert( 'Z' > 'A' ); // true alert( 'Glow' > 'Glee' ); // true alert( 'Bee' > 'Be' ); // true
大文字のA
は小文字のa
とはイコールじゃない。aの方が後。理由は小文字は内部のencoding table(Unicode)では、大文字より後にあるから。
alert( '2' > 1 ); // true, string '2' becomes a number 2 alert( '01' == 1 ); // true, string '01' becomes a number 1 alert( true == 1 ); // true alert( false == 0 ); // true
== と === の違い
let a = 0; alert( Boolean(a) ); // false let b = "0"; alert( Boolean(b) ); // true alert(a == b); // true!
上記2つの比較はtrueになる。なぜなら文字列が0に変換されるから。 ただ下記はfalseになる。
alert(a === b); // false!
== は、型を変換した値同士の比較だけど、=== は、型を変換することなく比較をして真偽値を返す。
alert( 0 == false ); // true alert( '' == false ); // true alert( 0 === false ); // false, because the types are different
論理演算子
- ORは、trueをさがしにいく
alert( true || true ); // true alert( false || true ); // true alert( true || false ); // true alert( false || false ); // false
result = value1 || value2 || value3;
左から実行していき、それぞれの項が、booleanに変換される。もしtrueがあれば、booleanに変換前の値を返す。すべてfalseだったら、最後の項を返す。
let x; true || (x = 1); alert(x); // undefined, because (x = 1) not evaluated
let x; false || (x = 1); alert(x); // 1
- ANDは、falseをさがしにいく
alert( true && true ); // true alert( false && true ); // false alert( true && false ); // false alert( false && false ); // false
result = a && b;
result = value1 && value2 && value3;
左から実行していき、それぞれの項が、booleanに変換される。もしfalseがあれば、booleanに変換前の値を返す。すべてtrueだったら、最後の項を返す。
// if the first operand is truthy, // AND returns the second operand: alert( 1 && 0 ); // 0 alert( 1 && 5 ); // 5 // if the first operand is falsy, // AND returns it. The second operand is ignored alert( null && 5 ); // null alert( 0 && "no matter what" ); // 0
- ANDは、ORの前に実行される
alert( 5 || 1 && 0 ); // 5
1 && 0
-> 0を返す。
5 || 0
-> 5を返す。
loop
while for のcounter 変数のスコープ
ループ内がスコープ範囲。
for (let i = 0; i < 3; i++) { alert(i); // 0, 1, 2 } alert(i); // error, no such variable
let i = 0; for (i = 0; i < 3; i++) { // use an existing variable alert(i); // 0, 1, 2 } alert(i); // 3, visible, because declared outside of the loop
break
最初で条件判定したいときは、while() 最後で条件判定したいときは、do while() 中間で条件判定したいときは、while(true) + break
let sum = 0; while (true) { let value = +prompt("Enter a number", ''); if (!value) break; // (*) sum += value; } alert( 'Sum: ' + sum );
continue
for (let i = 0; i < 10; i++) { // if true, skip the remaining part of the body if (i % 2 == 0) continue; alert(i); // 1, then 3, 5, 7, 9 }
Labels for break/continue
深いネストからbreakするのに使える
labelName: for (...) { ... }
例
for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { let input = prompt(`Value at coords (${i},${j})`, ''); // what if I want to exit from here to Done (below)? } } alert('Done!');
単なるbreakだと一階層上にbreakするだけで、グローバルにはbreakできない。
outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { let input = prompt(`Value at coords (${i},${j})`, ''); // if an empty string or canceled, then break out of both loops if (!input) break outer; // (*) // do something with the value... } } alert('Done!');
- continueも上記のような使い方が可能。
- labelはgotoではないので、以下のような使い方はできない。
break label; // jumps to label? No. label: for (...)
function
function name(parameters, delimited, by, comma) { /* code */ }
関数
- 関数は関数外の変数にアクセスできる。でも逆は無理。
- 関数は値を返す。でも値がなかったら、
undefined
を返す。
default 値の設定
function showMessage(from, text = "no text given") { alert( from + ": " + text ); } showMessage("Ann"); // Ann: no text given
デフォルト値のサポートは古いJavascriptではされていなかったので、以下のようなコードを使って再現していた。
function showMessage(from, text) { if (text === undefined) { text = 'no text given'; } alert( from + ": " + text ); }
function showMessage(from, text) { // if text is falsy then text gets the "default" value text = text || 'no text given'; ... }
return
function doNothing() { return; } alert( doNothing() === undefined ); // true
何も返さない return
は、return undefined
と同じ。( undefinedを返してるのと同じ )
関数定義と関数表現
関数定義
function sayHi() { alert( "Hello" ); }
関数表現
let sayHi = function() { alert( "Hello" ); };
function sayHi() { alert( "Hello" ); } alert( sayHi ); // shows the function code
上記を実行すると、
function sayHi() { alert( "Hello" ); }
が返る。
let sayHi = function() { alert( "Hello" ); }; alert( sayHi ); // shows the function code
上記を実行すると
function () { alert( "Hello" ); }
が返る。
sayHi
というのは、()
がついてないので、関数を実行したわけではない。多くのプログラミング言語では関数名で実行されるが、Javascriptはそうではない。
Javascriptでは、関数も値なので、値として対処しなければならない。
上記の例が示しているのは、sayHi という変数に、文字列でソースコードが代入されているということである。
sayHi()
という風にすればコードを実行できる。ただそれでも値なので、以下のようなことが出来る。
function sayHi() { // (1) create alert( "Hello" ); } let func = sayHi; // (2) copy func(); // Hello // (3) run the copy (it works)! sayHi(); // Hello // this still works too (why wouldn't it)
上記で起こっていることとしては、まず関数が作られ、sayHiという変数に代入される。(2)で、sayHiという変数の中身(ソースコード)がfunc
という変数にコピーされる。もし、func = sayHi()
だったら sayHi()
の実行結果が func
に代入される。sayHiのソースコードではなく。
また、これは以下のように書いても同様の動きをする。
let sayHi = function() { ... }; let func = sayHi;
;
を関数定義につけなくていいのはなぜか?
function sayHi() { // ... } let sayHi = function() { // ... };
if {}, for {}, と同様に、code blockとして、function sayHi() {}
をあつかっているから。
関数表現の方は、コードブロックではなく、値を変数に入れている文なので ;
が必要。
コールバック
値として関数が、使われる例。
function ask(question, yes, no) { if (confirm(question)) yes() else no(); } function showOk() { alert( "You agreed." ); } function showCancel() { alert( "You canceled the execution." ); } // usage: functions showOk, showCancel are passed as arguments to ask ask("Do you agree?", showOk, showCancel);
この例でいうところの ask
がコールバック関数・コールバックと呼ばれるものである。
function ask(question, yes, no) { if (confirm(question)) yes() else no(); } - function showOk() { - alert( "You agreed." ); - } - function showCancel() { - alert( "You canceled the execution." ); - } - // usage: functions showOk, showCancel are passed as arguments to ask - ask("Do you agree?", showOk, showCancel); + ask( + "Do you agree?", + function() { alert("You agreed."); }, + function() { alert("You canceled the execution."); } + );
上記のように短く書くこともできる。
ask(...)
の中で呼ばれている関数は名前が無い、無名である。
これらの関数は ask(...)
の外からはアクセスできない。なぜなら変数に代入されているわけではないから。
関数表現と関数宣言の違い
関数表現は、その関数が実行されて使用可能になるときに作られる。 それに対して関数宣言はすべてのscript/code blockから使用可能である。Javascriptはscriptを実行する前に関数宣言を探しに行き関数を作り、それからscriptを実行する。
sayHi("John"); // Hello, John function sayHi(name) { alert( `Hello, ${name}` ); }
sayHi("John"); // error! let sayHi = function(name) { // (*) no magic any more alert( `Hello, ${name}` ); };
逆に言えば関数宣言は、そのblock内からじゃないと使用できない。
let age = 16; // take 16 as an example if (age < 18) { welcome(); // \ (runs) // | function welcome() { // | alert("Hello!"); // | Function Declaration is available } // | everywhere in the block where it's declared // | welcome(); // / (runs) } else { function welcome() { // for age = 16, this "welcome" is never created alert("Greetings!"); } } // Here we're out of curly braces, // so we can not see Function Declarations made inside of them. welcome(); // Error: welcome is not defined
それに対して関数表現だと、
let age = prompt("What is your age?", 18); let welcome; if (age < 18) { welcome = function() { alert("Hello!"); }; } else { welcome = function() { alert("Greetings!"); }; } welcome(); // ok now
上記のように、変数に代入されているので、block外からも使用できる。
結局どっちを利用したらいいのか。
上記に合わせてケースバイケース
Arrow関数
(...args) => expression
は、評価して結果を返す。(...args) => {expression}
は、bracketのおかげで複数の文を関数内に書くことができる。ただなんらか値を返す必要がある。
let func = (arg1, arg2, ...argN) => expression
は、以下と一緒
let func = function(arg1, arg2, ...argN) { return expression; }
Reference from
https://javascript.info https://developer.mozilla.org/ja/docs/Web/JavaScript/Strict_mode