【GO】Golangの勉強を始めたから殴り書きのメモ~その2
つづき。 tour.golang.org
Pointer
ポインタは値のメモリアドレスを指す。→ 値が保存されてる場所
- 定義
// ゼロ値は nil var p *int
package main import "fmt" func main() { i, j := 42, 2701 p := &i // pにiのポインタを代入 fmt.Println(p) // 0x40e020 // iのポインタを通して、値を取得 fmt.Println(*p) // 42 // iのポインタを通して、値をセット *p = 21 // メモリアドレスの値が変更されたからiの値も変わる fmt.Println(i) // 21 p = &j // pにjのポインタを代入 *p = *p / 37 // jのポインタを通して、値を更新 fmt.Println(j) // 73 }
Structs
struct (構造体)は、フィールド( field )の集まり。
package main import "fmt" type Vertex struct { X int Y int } func main() { fmt.Println(Vertex{1, 2}) }
ドットつなぎでアクセスできるよ
package main import "fmt" // 構造体ってやつを定義 type Vertex struct { // 構造体を持つフィールドを定義 X int Y int } func main() { v := Vertex{1, 2} fmt.Println(v.X) // 1 v.X = 4 fmt.Println(v.X) // 4 }
構造体のポインタ
package main import "fmt" type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} p := &v // vのポインタを代入 p.X = 1e9 // 本来は(*p).Xのように書けるが、p.Xで同じ意味になる fmt.Println(v) // {1000000000 2} }
初期値の割り当て
package main import "fmt" type Vertex struct { X, Y int } var ( v1 = Vertex{1, 2} // 普通に v2 = Vertex{X: 1} // Xだけ v3 = Vertex{} // 両方入れない p = &Vertex{1, 2} // &をつけるとポインタ ) func main() { fmt.Println(v1, p, v2, v3) // {1 2} &{1 2} {1 0} {0 0} }
Arrays
宣言と代入
package main import "fmt" func main() { // 配列は固定長 var a [2]string // string型の2個の変数の配列を宣言 a[0] = "Hello" a[1] = "World" fmt.Println(a[0], a[1]) // Hello World fmt.Println(a) // [Hello World] // 宣言と代入 primes := [6]int{2, 3, 5, 7, 11, 13} // [2 3 5 7 11 13] fmt.Println(primes) }
Slices
package main import "fmt" func main() { // スライスは可変長 primes := [6]int{2, 3, 5, 7, 11, 13} // [low:high]を指定するよ var s []int = primes[1:4] fmt.Println(s) // [3 5 7] }
- スライスは配列への参照
package main import "fmt" func main() { // 配列を生成 names := [4]string{ "John", "Paul", "George", "Ringo", } fmt.Println(names) // [John Paul George Ringo] a := names[0:2] b := names[1:3] fmt.Println(a, b) // [John Paul] [Paul George] b[0] = "XXX" fmt.Println(a, b) // [John XXX] [XXX George] // 配列の値も変更される(=スライスは配列への参照) fmt.Println(names) // [John XXX George Ringo] }
- スライスのいろんな宣言と代入
package main import "fmt" func main() { q := []int{2, 3, 5, 7, 11, 13} fmt.Println(q) r := []bool{true, false, true, true, false, true} fmt.Println(r) s := []struct { i int b bool }{ {2, true}, {3, false}, {5, true}, {7, true}, {11, false}, {13, true}, } fmt.Println(s) }
- ちょっと変わった定義
package main import "fmt" func main() { s := []int{2, 3, 5, 7, 11, 13} // 普通に s = s[1:4] fmt.Println(s) // [3 5 7] // 下限を指定しない s = s[:2] fmt.Println(s) // [3 5] // 上限も下限を指定しない s = s[:] fmt.Println(s) // [3 5] }
- 長さ(length)と容量(capacity)
package main import "fmt" func main() { s := []int{2, 3, 5, 7, 11, 13} printSlice(s) // len=6 cap=6 [2 3 5 7 11 13] // Slice the slice to give it zero length. s = s[:0] printSlice(s) // len=0 cap=6 [] // Extend its length. s = s[:4] printSlice(s) // len=4 cap=6 [2 3 5 7] // Drop its first two values. s = s[2:] printSlice(s) // len=2 cap=4 [5 7] var s2 []int // スライスのゼロ値は[] fmt.Println(s2, len(s2), cap(s2)) // [] 0 0 if s2 == nil { fmt.Println("nil!") } } func printSlice(s []int) { fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) }
- make関数を使ってスライスを作る
package main import "fmt" func main() { // 長さが5のスライス a := make([]int, 5) printSlice("a", a) // a len=5 cap=5 [0 0 0 0 0] // 長さ0,容量5のスライス b := make([]int, 0, 5) printSlice("b", b) // b len=0 cap=5 [] c := b[:2] printSlice("c", c) // c len=2 cap=5 [0 0] d := c[2:5] printSlice("d", d) // d len=3 cap=3 [0 0 0] } func printSlice(s string, x []int) { fmt.Printf("%s len=%d cap=%d %v\n", s, len(x), cap(x), x) }
- スライスに要素を追加
package main import "fmt" func main() { var s []int printSlice(s) // len=0 cap=0 [] // append works on nil slices. // 第一引数が加える元、第二引数以降は可変長の加える変数 s = append(s, 0) printSlice(s) // len=1 cap=2 [0] // The slice grows as needed. s = append(s, 1) printSlice(s) // len=2 cap=2 [0 1] // We can add more than one element at a time. s = append(s, 2, 3, 4) printSlice(s) // len=5 cap=8 [0 1 2 3 4] } func printSlice(s []int) { fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) }
- Range
package main import "fmt" var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { // iはインデックス。vはその要素。 for i, v := range pow { fmt.Printf("2**%d = %d\n", i, v) } }
- 代入しない
package main import "fmt" func main() { pow := make([]int, 10) // ", v"を書かなければ代入を行わない for i := range pow { pow[i] = 1 << uint(i) // == 2**i } // "_"で代入を行わない for _, value := range pow { fmt.Printf("%d\n", value) } }
Map
package main import "fmt" type Vertex struct { Lat, Long float64 } var m map[string]Vertex func main() { // make関数を使ってMapを作成 m = make(map[string]Vertex) m["Bell Labs"] = Vertex{ 40.68433, -74.39967, } fmt.Println(m["Bell Labs"]) // {40.68433 -74.39967} }
package main import "fmt" type Vertex struct { Lat, Long float64 } // mapリテラル var m = map[string]Vertex{ "Bell Labs": Vertex{ 40.68433, -74.39967, }, "Google": Vertex{ 37.42202, -122.08408, }, } func main() { fmt.Println(m) // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}] }
package main import "fmt" type Vertex struct { Lat, Long float64 } // さらに省略 var m = map[string]Vertex{ "Bell Labs": {40.68433, -74.39967}, "Google": {37.42202, -122.08408}, } func main() { fmt.Println(m) }
- マップの操作
package main import "fmt" func main() { // make関数でmapを作る m := make(map[string]int) m["Answer"] = 42 fmt.Println("The value:", m["Answer"]) // The value: 42 // 上書き m["Answer"] = 48 fmt.Println("The value:", m["Answer"]) // The value: 48 // 要素を消す delete(m, "Answer") // valueのゼロ値が入る fmt.Println("The value:", m["Answer"]) // The value: 0 // キーに対する要素が存在するかどうかは、2つの目の値で返す v, ok := m["Answer"] fmt.Println("The value:", v, "Present?", ok) // The value: 0 Present? false }
package main import ( "fmt" "math" ) func compute(fn func(float64, float64) float64) float64 { return fn(3, 4) } func main() { // 関数に関数を渡せる // 関数も変数として扱える hypot := func(x, y float64) float64 { return math.Sqrt(x*x + y*y) } fmt.Println(hypot(5, 12)) // 13 fmt.Println(compute(hypot)) // 5 fmt.Println(compute(math.Pow)) // 81 }
【GO】Golangの勉強を始めたから殴り書きのメモ~その1
A tour of Go を基にメモ。 誤字脱字はすみません。 いつか綺麗に書く。多分。 tour.golang.org
- Goのプログラムは、パッケージ( package )で構成される。
- mainのmain()が実行される 次の二つは同じ
import "fmt" import "math/rand"
import ( "fmt" "math/rand" )
- 最初の文字が大文字で始まる名前は、外部のパッケージから参照できるエクスポート(公開)された名前( exported name )です。
=> 大文字始まりにすれば、外部パッケージから参照できる。
関数の定義
- 普通にかく
// func 関数名(引数a aの型, 引数b bの型) int { ... } func add(x int, y int, z int) int { return x + y + z }
- 引数の型が同じなら省略できる
// 上のやつと同じ func add(x, y, z int) int { return x + y + z }
- 二つ戻り値もてるよ
func swap(x, y string) (string, string) { return y, x } func main() { // 関数の戻り値を代入 a, b := swap("World", "Hellow") println(a, b) // Hellow World }
- 戻り値に名前つけられるよ
// xとyが戻り値。これも戻り値の型が同じだと省略できる。 // 短い関数だけで使おう。可読性が落ちるんだってさ。 func super() (x, y string) { x = "Java" y = "おじさん" return // naked return って言うらしい } func main() { fmt.Println(super()) // Java おじさん }
変数の定義
- 普通に宣言
package main import "fmt" // パッケージ内で宣言できるよ。 // 変数も同じ型なら省略できるんだって。 var c, python, java bool func main() { // 関数内でも宣言できるよ。 var i int // 宣言だけした場合、intは0, boolはfalseが入るよ。 fmt.Println(i, c, python, java) // 0 false false false }
- 宣言して代入
package main import "fmt" // 宣言して代入 var i, j int = 1, 2 func main() { // 関数内でも宣言して代入 var c, python, java = true, false, "no!" fmt.Println(i, j, c, python, java) // 1 2 true false no! }
- 省略した宣言して代入
package main import "fmt" // 関数の外では省略した書き方はできない func main() { // 普通の宣言して代入 var i, j int = 1, 2 // 省略した書き方 k := 3 c, python, java := true, false, "no!" fmt.Println(i, j, k, c, python, java) //1 2 3 true false no! }
- 変数のゼロ値 宣言したけど初期値入れないとゼロ値が与えられる。
数値型(int,floatなど): 0 bool型: false string型: "" (空文字列( empty string ))
- 型の変換 T(v)・・・vをT型に変換する時
var i int = 42 // int -> float64 var f float64 = float64(i) // float64 -> unit var u uint = uint(f)
// 上のやつの省略系 i := 42 f := float64(i) u := uint(f)
定数の定義
- 普通に定義
package main import "fmt" // 関数外でも定義できるよ // :=は使えない const Pi = 3.14 func main() { // 関数内でも:=は使えない const World = "世界" fmt.Println("Hello", World) fmt.Println("Happy", Pi, "Day") const Truth = true fmt.Println("Go rules?", Truth) }
For文
- 一般的な形
func main() { sum := 0 // iが10以上になったら終わり // iの初期値は0 // 一周したらiをインクリメント(後処理ステートメント) for i := 0; i < 10; i++ { sum += i } fmt.Println(sum) // 45 }
- 初期化とかなくてもええんやで
func main() { sum := 1 // 初期化と後処理ステートメントはなくてもいい for ; sum < 1000; { sum += sum } fmt.Println(sum) }
// 初期化と後処理ステートメントないならセミコロンもいらん func main() { sum := 1 for sum < 1000 { sum += sum } fmt.Println(sum) }
if文
- 一般的なif
func sqrt(x float64) string { // ()はいらない if x < 0 { return sqrt(-x) + "i" } return fmt.Sprint(math.Sqrt(x)) } func main() { fmt.Println(sqrt(2), sqrt(-4)) }
- 簡単なステートメントを書ける
func pow(x, n, lim float64) float64 { // 変数vを宣言できるよ // このifの中でしか変数vは使えないよ if v := math.Pow(x, n); v < lim { return v } return lim }
- if-else
func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v // elseも使えるね } else { fmt.Printf("%g >= %g\n", v, lim) } // can't use v here, though return lim }
switch文
package main import ( "fmt" "runtime" ) func main() { fmt.Print("Go runs on ") // if文と同じように変数osを定義できる switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") // breakはなくても良いのだよ case "linux": fmt.Println("Linux.") default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.", os) } }
func main() { t := time.Now() // こんな書き方もできる。 // switch true {...} と同じ switch { case t.Hour() < 12: fmt.Println("Good morning!") case t.Hour() < 17: fmt.Println("Good afternoon.") default: fmt.Println("Good evening.") } }
Defer(遅延させる)
package main import "fmt" func main() { // 引数の評価はされるけど、呼び出し元の関数がreturnするまで延期 defer fmt.Println("world") fmt.Println("hello") } // 出力 // hello // world ★ helloよりも後に実行される
- 複数のDefer
package main import "fmt" func main() { fmt.Println("counting") for i := 0; i < 10; i++ { // たくさんdeferする // 先入れ後出し方式 // 箱の中に順番にモノを入れていって、上から順番に出す感じです defer fmt.Println(i) } fmt.Println("done") } /* 出力 counting done 9 8 7 6 5 4 3 2 1 0*/
続く。。。
【Java】Optionalとは仲良くした方がいいよって話
こんにちは、かっつんです!
Java8でOptionalが導入されて久しいですが、Optionalと仲良くできていますか?
私は好きです、非常に。何ならなんでもOptionalにしてしまいがちなくらい好きです、、、
で、Optionalってなんなのさ?
ドキュメントによると、
null以外の値が含まれている場合も含まれていない場合もあるコンテナ・オブジェクトです。
引用: Optional (Java Platform SE 8)
うん、言いたいことはなんとなくわかりますね、、、
あるかないかわからないからOptionalさんがラップして代わりに表現してくれるということみたいですね。
え、nullチェックしたらよくね?
nullかもしれない値が渡ってくるならnullチェックすればいんじゃね?
わざわざOptionalとか言うよくわからんやつ使うのなんてめんどくさいだけじゃん。って思いません?
私もここまでの話だけならそう思います。実際に事足りますしね。。。
でもここからがOptionalさんの本当の力の見せ所なんです!
例えば次のような処理を行いたいとき
1 DBからIDで果物名を取得 2 #1で果物名が取得できたら、「"私は#{果物名}+が大好きです"」という文字列に加工して返却する。 取得できなかった場合は、「"果物食べたいな〜"」という文字列を返却する。
Optionalを使わない場合
public String getFruits(Long id) { String name = findById(id); // findByIdの戻り値はString型 if (name == null) { returen "果物食べたいな〜"; } returen "私は" + name + "が大好きです"; }
Optionalを使った場合
public String getFruits(Long id) { // findByIdの戻り値はOptional<String> returen findById(id).map(name -> "私は" + name + "が大好きです") .orElse("果物食べたいな〜"); }
ん!???何とも簡潔、、、
(画面幅の都合で改行してますが)ワンライナー、、、素晴らしい。
少しだけ、Optionalを使った場合の解説をすると、
findById(id)
の中身があった時は、.map()
内の処理が実行され、
中身がなかった時は.orElse()
内の処理が実行されるのです。
このコードの可読性もさることながら、
Optionalの一番のメリットはやはりnullを気にしなくて良いこれに尽きると思います(個人的に)
ってことは、もうnullを恐れなくていいのか!!
そうです! ヌルポを出して、ガッ!ってされていた時代はもう古き良き時代の産物として、明日からみんなOptional使ってね。
他にも色々なメソッドとかあるから紹介しておくコーナー
Optional.of()
やOptional.ofNullable()
使えばOptional型に変換できるよ!Optionalが空っぽの時は、nullじゃなくて、
Optional.empty()
だよ!.orElse()
以外にも、.orElseGet()
使えば
.orElseGet(() -> { Fruits fruits = new Fruits(); fruits.setName("オレンジ"); returen fruits; })
のようにインスタンスを返却したり、
.orElseThrow()
使えば
.orElseThrow(() -> new RuntimeException("該当するフルーツがないよ"));
みたいに例外を投げることも可能だよ!
isPresent()
を使えば中身があればtrue
、なければfalse
のbool値を返してくれるよ!ifPresent()
を使うと中身がある場合に、処理が行えるよ。戻り値はvoidだよ!
最後に
Optional型で取得したのに、即get()したらあかんからね!!!
【Java】配列⇄リスト、リスト⇄セット、リスト⇄マップの変換って忘れがちじゃない?
こんにちは、かっつんです!
普段コードを書いてる時もJavaのコレクション系の変換って、度々必要になるけどよく忘れるよね?私は忘れます。。。
そんなあなたに、今日は配列⇄リスト、リスト⇄セット、リスト⇄マップの変換についてご紹介します!(という名の私の備忘録です!笑)
配列からリスト
// 変換したい配列 String[] stringArray = { "あ", "いい", "うぅ", "エー", "オウフ" }; // Listに変換 List<String> list = Arrays.asList(stringArray);
Arrays.asList()の引数に配列を渡すことで簡単に変換できます!
リストから配列
// 変換したいList List<String> strings = Arrays.asList("あ", "いい", "うぅ", "エー", "オウフ"); // 配列に変換 String[] array = strings.toArray(new String[strings.size()]);
ListのtoArrayメソッドを使うことでこちらも簡単に変換できます。[]
には配列のサイズ(=変換するリストのサイズ)
を指定します。
リストからセット
// 変換したいList List<String> strings = Arrays.asList("あ", "いい", "うぅ", "エー", "オウフ"); // Setに変換 Set<String> setString = new HashSet<>(strings);
こちらも引数にリストを渡すことで簡単に変換ができます!
セットからリスト
// 変換したいSet Set<String> strings = new HashSet<String>() {{ add("あ"); add("いい"); add("うぅ"); add("エー"); add("オウフ"); }}; // Listに変換 List<String> list = new ArrayList<>(strings);
はい、こちらも引数に渡すことで変換可能です!
リストからマップ
class Dto { final long id; final String val; Dto(long id, String val) { this.id = id; this.val = val; } @Override public String toString() { return String.format("Dto(%d, %s)", id, val); } } // 変換するList List<Dto> dtos = IntStream.rangeClosed(1, 10).mapToObj(id -> new Dto(id, UUID.randomUUID().toString())).collect(Collectors.toList()); // Mapに変換 Map<Long, Dto> dtoMap = dtos.stream().collect(Collectors.toMap(dto -> dto.id, dto -> dto, (dto1, dto2) -> dto1));
toMap()
の第一引数でキーになる値を渡し、第二引数でバリューを渡します。
キーに重複がある場合、IllegalStateException
が発生します。
第三引数で、条件を指定します。(dto1, dto2) -> dto1
は先にセットしたバリューを優先する条件です。
マップからリスト
// 変換したいMap(リストからマップで作成したもの) Map<Long, Dto> dtoMap = dtos.stream().collect(Collectors.toMap(dto -> dto.id, dto -> dto, (dto1, dto2) -> dto1)); // Listに変換 List<Dto> Dtos = new ArrayList<>(dtoMap.values());
Mapのバリューをリストに変換するには、values()
メソッドを使っMapのバリューのコレクションを作成します。
作成したコレクションをnew ArrayList<>()
の引数に渡すことで変換可能です!
【Zsh】お?zshだと^が使えない?問題
こんにちは、かっつんです!
Zshが、次期macOS Catalinaからデフォルトシェルになることから、
これまでのbashなどから切り替えを行なった方も多くいらっしゃるのではないでしょうか?
私も切り替えを済ませ、いつも通りコーディングをしていたのですが、
git reset --hard HEAD^
を実行した時に。。。
❯ git reset --hard HEAD^ zsh: no matches found: HEAD^
あれ、^
使えなくね?なんで?お?ってなったのでご紹介!(という名目の備忘録!笑)
❯ git reset --hard HEAD\^
単純にエスケープすることで、コマンドが通るようになりました!
zshって、^
そのままでは使えないんですね!勉強になりました!
あせった、、、笑
【Redis】redis-cliでマルチバイト言語が文字化けする問題
こんにちは、かっつんです!
業務でRedisを使っていた時のお話。
保存した値をredis-cliで確認しようとしたら、日本語が表示できない、、、どうしよ。
ってなったのでご紹介します!
発生した事象
❯ redis-cli 127.0.0.1:6379> SET key こんにちは、世界 OK 127.0.0.1:6379> GET key "\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf\xe3\x80\x81\xe4\xb8\x96\xe7\x95\x8c"
解決法
❯ redis-cli --raw 127.0.0.1:6379> SET key こんにちは、世界 OK 127.0.0.1:6379> GET key ”こんにちは、世界”
--raw
オプションをつけることで解決します!
未経験からでもエンジニアになるよ。って話
こんにちはかっつんです!
今日はプログラミング未経験からエンジニアになる方法についてお話しようと思います!
未経験の定義
この記事での未経験とは、 プログラミング未経験 のことです。
求人票などで目にする未経験は、
プログラミングの実務経験がない(=プログラミングちょっとわかる)であることが圧倒的に多い印象です。
そもそも未経験からエンジニアになれるの?
おそらく、未経験からエンジニアを目指す人が最初に関心を持つところだと思います。
結論からお伝えすると、未経験からでもエンジニアになれます。
ただし、未経験でエンジニアはほぼ無理です。 コードを一切書いたことがないのにエンジニアになることはかなり厳しいでしょう。なれなくは無いけど。。。なっても楽しくないよ多分。
少しの学習は必要ですが、エンジニアになることがゴールであれば、そのハードルは割と高くないです。
むしろ業界自体が人で不足で、今後もその傾向は続くという試算も出されているようです。
私自身が、文系出身、プログラミング経験がない状態からweb系のエンジニアになっているので、
信ぴょう性は高いです。笑
ですので、未経験からエンジニアになれるのか?という問いに対しては、
YES以外の返答はありません!現に、私以外にも未経験からエンジニアになっている方は非常に多くいらっしゃいます!
エンジニアになる方法
少し前置きが長くなりましたが、未経験からエンジニアになる方法をお話します!(ここからが本題)
1.プログラミングスクールに通う
最も確実と言える方法ではないでしょうか?
プログラミング学習の支援はもちろんのこと、 転職サポートもしてくれるプログラミングスクールが非常に多いです。
スクールによっては転職保証制度なるものが付いていて、 仮に転職に失敗した場合でも、受講料が全額返金されるキャンペーンを行なっているようです!
ただし、スクールを通してエンジニアに転職した場合、
なんてこともあるようです。
"転職後の給料が安い"と"言語の選択肢が狭い"は、転職活動の際に、しっかり軸を持っていればなんとかなるような気はしますが、 "エンジニアとして働けない"はきつそうですね。
スクールで紹介される求人にはプロダクトマネージャーや営業など、エンジニア職ではない求人も多くあるようです。
なんのためにコードかけるようになったのでしょうか。。。そもそもスクール行かなくてもなれるよたぶん、、、
また、スクールには受講期間があるわけで、
スクール側もいつまでも受講生を残しておくわけには行きませんよね、、、
言葉は悪いですが、ある程度のスピードで受講生を捌かなけらばなりません。
次から次へと受講生が入ってくる中で、気長に良い求人が出るまで、、、みたいなことは難しそうです。
そして何より、受講料です。80万円!?...高過ぎです。
本当に通う人いるの??ってレベルですが、受講を希望する方は後を絶えないようです。。。(プログラミングスクール開こうかな。)
3ヶ月間でみっちり学習するコースでは、バイトする時間もないでしょうし、その間の生活費、定期代、パソコン買うならその代金も含めると余裕で120〜130万円くらいかかるんじゃないかな?
これを安いと思えるか、高いと思うかは人それぞれですが、個人的には高すぎて払いたく無いです。(貧乏なので払えないです、、、)
この大金があれば、プログラミングを学習する選択肢は他にもたくさんあるので、申し込みをする前に考えてみて欲しいです。なかには無料のプログラミングスクールなんてものもあるのだとか!
ただし、ネット上には胡散臭いプログラミング学習サービスが結構あったりするので、 そーゆー心配をしたくない人は、高額な受講料を払ってでも、プログラミングスクールに入るメリットは大きいのではないでしょうか!
2.独学からの就活
最近は独学でプログラミングを学習し、エンジニアに転職される方も多くいるようです!
独学でエンジニア転職するならば、
ざっくりこんな感じのステップになると思います!
プログラミングスクールのところで少しだけ述べたのですが、Progate(プロゲート)やドットインストール、Udemy(ユーデミー)などの プログラミング学習サービスも非常に充実しており、スクールと比べるとどれも安価です。
独断と偏見ですが、独学が向いているのはこんな人かな〜って思います!
- 学習の目的を明確にできてる人
- グーグル検索がうまく使える人
- 英語のドキュメントもちゃんと読む人
"グーグル検索がうまく使える人"はふざけているように思いますが、全くふざけて無いです。
プログラミングの知識について言えば、スクールのカリキュラムに掲載されていて、グーグル検索に出てこないもの何てありません。もし出てこないとしたら、誰も使って無いからです。
独学は不安かもしれませんが、
- 結局のところプログラミングって何をやればいいのか、
- どこにコードを書けばいいのか、
- どーやって書いたコードを動かすのか、
- 作ったプロダクトをどーやって公開するのか、
さえ分かれば、あとはコードを書いた量に比例して出来るようになるものだと私は思っています。(実務もすぐに出来るということでは無いです。)
就職活動も、ポートフォリオを公開して、Wantedlyなどのサービスを使えば比較的スムーズに転職活動を行うこともできます!
どの方法でも共通で言えることですが、ポートフォリオを作成することは非常に大切です。
エンジニアとしての就職・転職を考えるのであれば、必ず、ポートフォリオを作成した上で臨みたいです!
ポートフォリオって何作ったらいいの?って悩んだら、既存サービスのコピーサイトを作りましょう!
独学でエンジニアを目指すと勉強開始から就職までのステップを圧倒的に早めることも出来るし、受講期間などの縛りが無いので、自分のペースで学習を進めることもできます!
仕事などと並行して、自分のペースでエンジニアを目指すならばこの方法が良いかなと思います。
3.未経験から直でエンジニア就職【要注意】
正直にお伝えすれば、オススメできません。
なぜなら、ハズレくじを引く確率が圧倒的に高いからです。
最近エンジニアの求人で、未経験の方も歓迎するようなもの多く目にしますが、皆さんのイメージするコードを書くエンジニアである可能性は何パーセントほどでしょうか。。。
もちろんゼロではありませんが、
ほとんどの場合、テスターなどのほとんどプログラミングの知識を必要としない作業を延々とやることになり、 最悪の場合、そのまま客先に派遣され、ないにもわからないままタスクを振られるケースもあると耳にしたことがあります(まあ滅多にはないと思います)
全てが全てではありませんので、
現場に出るまで研修がしっかりしている企業や、
先輩エンジニアによるOJTが体系化されている企業ももちろんあります。
現に、全くの未経験でエンジニアに就職し、先輩エンジニアにほぼマンツーマンに近い形で業務を行なっている人も身近にいらっしゃいます。
あたりを引いたら非常によさそうだなって思います。 勉強しながら収入を得て、
並行して実務経験が積み重なり、
無職でいる期間がほぼないに等しい、
夢のようです。
ただし、ハズレを引いたら非常に辛い思いをすることになるので、この方法でエンジニアを目指すのであれば、企業選びを慎重に慎重を重ねて欲しいです。
最後に!
これからエンジニアを目指そうかな〜っと思ってる人に、なるほどな〜って思っていただければ幸いです!
何れにしても、エンジニアを仕事とする上では、継続して学習することが必要そうですね!