Yuki's Tech Blog

仕事で得た知見や勉強した技術を書きます。

TSとGoの構文をざっくり比べてみた

目次

インデント

TSではインデントは2つ、Goは4つです。

セミコロン

TSでは基本的にはセミコロンを書きます(プロジェクトによって書かなかったりします)。Goの場合、セミコロンは書かなくて大丈夫です。

文字列の結合

TS

加算演算子でもできますが、JSのテンプレートリテラルを使うと簡単にできます。

const firstName = "Ken";
const lastName = "Tanaka";
const fullName = `${lastName} ${firstName}`;

console.log(fullName); // => Tanaka Ken

Go

Goにテンプレートリテラルはないです。関数を使って文字列を結合する方法もありますが、Goでは加算演算子を使うのが一番シンプルで簡単です。ちなみにGoでは文字列はダブルクオーテーションで囲みます。

package main

import . "fmt"

func main() {
    f := "Ken"
    l := "Tanaka"
    fullName := l + " " + f
    Println(fullName) // => Tanaka Ken
}

Goでテンプレートリテラル風に出力したい場合、Printfを使います。

package main

import . "fmt"

func main() {
    f := "Ken"
    l := "Tanaka"
    Printf("%s %s", l, f) // => Tanaka Ken
}

変数

TS

let lastName: string
lastName = "Tanaka"

console.log(lastName); // => Tanaka

Go

package main

import . "fmt"

func main() {
    // var l string = "Tanaka" or var l = "Tanaka"と書いても良い(初期化されるなら何の値が代入されるか明確なので、型を省略できる)。
    // 以下2行をまとめて、l := "Tanaka"と書いても良い
    var l string
    l = "Tanaka"

    Println(l) // => Tanka
}

2つのコードを比較

  • TSもGoも変数を初期化する場合、何の値が代入されるか明確なので、型を省略することができます。
  • 変数を定義する場合、TSではlet、Goではvarを使います。
  • 変数名の後ろに型を書く場合、Goでは変数名の末尾に : をつけません。TSの場合、型アノテーションをする場合は、 : を変数名の後ろにつけます。
  • Goでは変数の初期化を簡潔に書くことができます(:=)。Goではこの書き方が主流です。
  • Goではスコープが狭い場合に限り、1文字の変数名が許されます。とはいえ、どんな値が入っているかが分かる名前をつけます。TSでも、何の値が入っているかが分かる名前をつけます。
  • 変数名はどちらもローワーキャメルケースで書きます。しかし、Goで変数をエクスポートしたい場合、変数名をアッパーキャメルケースにします。

定数

TS

const firstName = "Ken";

console.log(firstName); // => Ken

Go

package main

import . "fmt"

func main() {
    const f = "Ken"

    Println(f) // => Ken
}

2つのコードを比較

  • 定数を定義するときはどちらもconstを使っています(TSのconstは必ずしも定数とは言えないので変数として扱われます)。
  • TSのconstで宣言する定数は変数なので、変数名は基本的にはキャメルケースで定義します。しかし、APIのエンドポイントなど、本当の意味で定数として定義したい場合、constで変数宣言して、変数名をアッパースネークケースにします(CREATE_USER_URL等)。
  • Goでは定数の命名規則は決まっていないのかと思われるので、変数と同じでローワーキャメルケースとアッパーキャメルケースを使い分けます。

加算代入演算子、インクリメント演算子

TS

let count = 0;

count++;
count += 1;
console.log(count); // => 2

Go

package main

import . "fmt"

func main() {
    c := 0

    c++
    c += 1
    Println(c) // => 2
}

2つのコードを比較

  • 特に違いはないです。

出力

TS

const firstName = "Ken"
console.log(firstName);  // => "Ken"

Go

package main

import . "fmt"

func main() {
    f := "Ken"

    println(f) // => Ken
    Println(f) // => Ken
    Printf("お名前: %s", f) // => お名前: Ken
}

2つのコードを比較

  • TSでエラーとしてコンソールに出力したい場合、console.errorを使います。
  • Goではprintlnという組み込み関数が最初から使えますが、fmtパッケージのPrintlnの方が表示できるデータ型が多いので、そちらが主に使われます。

if文

TS

let count = 0;

if (count === 0) {
  count++;
} else if (count === 1) {
  count += 2;
} else {
  count = 0;
}

console.log(count); // => 1

Go

package main

import . "fmt"

func main() {
    c := 1

    if c == 0 {
        c++
    } else if c == 1 {
        c += 2
    } else {
        c = 0
    }

    Println(c) // => 3
}

2つのコードを比較

  • TSの条件部分は、truthy or falsyで判定される為、比較的自由に指定できます。Goの場合、truthyとfalsyの概念がおそらくないため、条件部分には論理型の値もしくは、論理型の値を返す式や関数呼び出しを指定します。
  • TSでは条件部分を丸括弧で囲みますが、Goでは囲みません。Goのif文の書き方はRubyに似てます。

TS

// let isOk: boolean
// let count: number
// let firstName: string
// 上の変数はそれぞれ別に定義しなくても、まとめて定義できます
let isOk: boolean, count: number, firstName: string;

isOk = true;
count = 1;
firstName = "Ken";

console.log(isOk, count, firstName) // => true 1 "Ken"

Go

package main

import . "fmt"

func main() {
    // Goで型を指定してまとめて変数宣言したい場合、丸括弧で囲む。
    var (
        isOk bool
        c    int
        f    string
    )

    isOk, c, f = true, 1, "Ken"

    Println(isOk, c, f) // => true 1 Ken
}

2つのコードを比較

  • 論理型はTSではboolean、Goではboolを用いて表します。
  • 数値型はTSではnumber、Goではint or float64を用いて表します。Goの数値型には整数型と小数点型があり、多くの種類が存在します。しかし、この2つをメインに使っていくため、この2つを覚えておけば大丈夫です。intは実装するOSやCPUに依存した整数型です。float64は小数点型です。
  • 文字列型はTSではstring、Goでもstringを用いて表します。

右辺と左辺が等しいか比較する

TS

let firstName = "Ken";

console.log(firstName === "Ken"); // => true
console.log(firstName === "Tarou"); // => false

console.log(firstName !== "Ken"); // => false
console.log(firstName !== "Tarou"); // => true

Go

package main

import . "fmt"

func main() {
    f := "Ken"
    Println(f == "Ken")   // => true
    Println(f == "Tarou") // => false

    Println(f != "Ken")   // => false
    Println(f != "Tarou") // => true
}

2つのコードを比較

  • 右辺と左辺が等しいかを確認する場合、TSでは厳密等価演算子(=== および !==)を使用します。Goでは比較演算子(== 及び !=)を使用します。Goの比較演算子Rubyに似てます。

論理演算子(論理和演算子論理積演算子)

TS

let initialCount = 0;
let count = 1;
let isOne = true;
let isTwo = false;

// どちらもtruthyな値の場合
console.log(count || isOne); // => 1
console.log(isOne || count); // => true
console.log(isOne && count); // => 1
console.log(count && isOne); // => true

// 片方がfalsyな値の場合
console.log(count || isTwo); // => 1
console.log(isTwo || count); // => 1
console.log(isTwo && count); // => false
console.log(count && isTwo); // => false

// どちらもfalsyな値の場合
console.log(initialCount || isTwo); // => false
console.log(isTwo || initialCount); // => 0
console.log(isTwo && initialCount); // => false
console.log(initialCount && isTwo); // => 0

Go

package main

import . "fmt"

func main() {
    i, c := 0, 1

    // どちらもtrueの場合
    // 比較演算子は、演算子の左右の値を比較してtrueかfalseの論理値で評価する演算子です。
    // そのため、比較演算子は、論理演算子のオペランドとして使うことができます。
    Println(true || true)   // => true
    Println(i < 1 || c > 0) // => true
    Println(true && true)   // => true
    Println(i < 1 && c > 0) // => true

    // 片方がfalseの場合
    Println(false || true) // => true
    Println(true || false) // => true
    Println(false && true) // => false
    Println(true && false) // => false

    // どちらもfalseな場合
    Println(false || false) // => false
    Println(false && false) // => false
}

2つのコードを比較

  • TSの論理和演算子(||)は、どちらもtruthyな値の場合、最初に評価したtruthyな値を返します。falsyな値が一つ含まれている場合、最初に評価したtruthyな値を返します。どちらもfalsyな値の場合、最後に評価したfalsyな値を返します。つまり、全ての値がfalsyな値の場合、最後に評価したfalsyな値を返します。truthyな値が一つでも含まれている場合、評価して初めて見つけたtruthyな値を返します。
  • TSの論理積演算子(&&)は、どちらもtruthyな値の場合、最後に評価した値を返します。最初がtruthyな値で最後がfalsyな値の場合、最後に評価したfalsyな値を返します。最初がfalsyな値で最後がtruthyな値の場合、最初に評価したfalsyな値を返します。どちらもfalsyな値の場合、最初に評価したfalsyな値を返します。つまり、全ての値がtruthyな場合、最後に評価したtruthyな値を返し、falsyな値が一つでも含まれている場合、評価して初めて見つけたfalsyな値を返します。
  • Goの論理演算子の場合、オペランド(演算対象の値)が論理型の値でないとエラーが出ます。TSほど論理演算子の書き方に自由度はないです。
  • Goの論理演算子は仕組み的には、TSと同じです。違いはGoの論理演算子オペランドには、論理型の値しか指定できないところです。

switch文

TS

let n = 2;

switch (n) {
  case 1:
    console.log("大吉です")
    break;
  case 2:
  case 3:
    console.log("吉です")
    break;
  default:
    console.log("凶です")
}

Go

package main

import . "fmt"

func main() {
    n := 3
    switch n {
    case 1:
        Println("大吉です")
    case 2, 3:
        Println("吉です")
    default:
        Println("凶です")
    }
}

2つのコードを比較

  • Goのswitch文はswitchとcaseが同じ列に存在してます。TSの場合、switchの最初の文字を基準としてcaseにインデントを設定します。
  • Goのswitch文のcaseには、複数値を指定できます。TSで同じことをやる場合、caseをもう一度書きます。
  • Goのswitch文のcaseには、breakが暗黙で入ります。TSの場合、明示的に書く必要があります。

import文

TS

import React from "react";
import { useForm } from "react-hook-form";

Go

package main

// import . "fmt"
// import "math/rand"
// import "time"
// 上の3つは丸括弧を使ってまとめて書ける
import (
    . "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().Unix())
    r := rand.Intn(10)
    Println(r)
}

2つのコードを比較

  • TSのimport文はfromをつけます。Goではfromを書きません。
  • TSのimport文ではモジュールから具体的に何をインポートするかを書きます。Goの場合、パッケージ名だけ書きます。
  • TSでは一つのモジュールから複数名前付きインポートすることができます。Goでは、複数のパッケージを一つのインポート文でまとめて書くことができます。TSにはそのような機能はないと思われます。

for文

TS

for (let i = 0; i < 3; i++) {
  console.log("hoge");
}

// TSだとfor文よりforEachを使う印象がある
[...Array(3).keys()].forEach((item) => {
  console.log("hoge")
})

Go

package main

import . "fmt"

func main() {
    for i := 0; i < 3; i++ {
        Println("hoge")
    }
}

2つのコードを比較

  • Goのfor文はif文と同じで丸括弧を書かなくて大丈夫です。TSは丸括弧を書きます。
  • Goのfor文のループで使う変数は := で定義します。

関数

TS

// 方法1: functionキーワードを使う
// function setUser (name: string, age: number) {
//   return {
//     name,
//     age,
//   }
// }

// 方法2: 関数式を使う。関数式をfunctionキーワードで書く(あまり使わない)
// 関数式では名前を省略できる。名前を持たない関数を無名関数と呼ぶ。
// const setUser = function(name: string, age: number) {
//   return {
//     name,
//     age,
//   }
// };

// 方法3: 関数式を使う。関数式をアロー関数で書く(よく使う)
// アロー関数を用いると、関数式の関数に名前をつけることはできません(常に無名関数)。
// 戻り値の型は省略できます。
const setUser = (name: string, age: number): {name: string, age: number}  => {
  return {
    name,
    age,
  }
};

const user = setUser("Ken", 25);
console.log(user);

Go

package main

import (
    . "fmt"
    . "strconv"
)

func main() {
    message := setMessage("Ken", 25) // => 名前: Ken, 年齢: 25
    Println(message)
}

// Goでは型が一致してないと演算できない。
// strconvパッケージを使って数値を文字列に変換すれば、演算できる。
func setMessage(name string, age int) string {
    message := "名前: " + name + ", 年齢: " + Itoa(age)
    return message
}

2つのコードを比較

  • TSにはいろいろな関数の書き方が存在します。Goではfuncキーワードを用いて関数を定義します。
  • TSとGoのどちらも関数の引数に型を必ず指定します。
  • TSの関数では、戻り値の型を省略できます。Goの場合、関数の戻り値の型は必須です。

感想

まだまだ比較できてない部分もあるので、見つけ次第、追記していきます!

参考記事

加算 (+) - JavaScript | MDN

【Golang】文字列の中で変数を展開する(テンプレートリテラル) | CODE MARINE

Go言語のprintln関数がシェルでファイルにリダイレクトしてくれなくてハマった

【5分レッスン】Go超入門コース#07 データ型 | キノコード

変数の宣言、変数への代入、変数の参照 : TypeScript | iPentec

Go言語の変数定義 - Qiita

論理積 (&&) - JavaScript | MDN

オペランド(被演算子)とは - 意味をわかりやすく - IT用語辞典 e-Words

論理演算子 | 論理型 (boolean) | プログラミング言語の比較 | hydroculのメモ

【Go入門】if文による条件分岐とtrue, false

Switch

【Go入門】Goの基本型 – 論理値型(Boolean types)

Goにおける等値と等価の考察(struct1==struct2と&struct1==&struct2とreflect.DeepEqual(struct1,struct2)とreflect.DeepEqual(&struct1,&struct2)) - Qiita

import - JavaScript | MDN

[...Array(n).keys()] はやめた方がいいのでは?

Go言語(golang) 関数 - golangの日記

関数と宣言 · JavaScript Primer #jsprimer

関数 - JavaScript | MDN

Goはオブジェクト指向言語だろうか? | POSTD

golang 文字列→数値、数値→文字列変換 - Qiita

他言語プログラマがgolangの基本を押さえる為のまとめ - Qiita

【Go】import 書き方まとめ - Qiita