20201122のGoに関する記事は8件です。

LeetCodeに毎日挑戦してみた 20. Valid Parentheses(Python、Go)

はじめに

無料英単語サイトE-tanを運営中の@ishishowです。

プログラマとしての能力を上げるために毎日leetcodeに取り組み、自分なりの解き方を挙げていきたいと思います。

Leetcodeとは

leetcode.com
ソフトウェア開発職のコーディング面接の練習といえばこれらしいです。
合計1500問以上のコーデイング問題が投稿されていて、実際の面接でも同じ問題が出されることは多いらしいとのことです。

Go言語入門+アルゴリズム脳の強化のためにGolangとPythonで解いていこうと思います。(Pythonは弱弱だが経験あり)

6問目(問題20)

20. Valid Parentheses

  • 問題内容(日本語訳)

文字列を考えるsだけで文字を含む'('')''{''}''['']'、入力文字列が有効であるかどうかを決定。

入力文字列は、次の場合に有効です。

  1. 開いたブラケットは、同じタイプのブラケットで閉じる必要があります。
  2. 開いたブラケットは正しい順序で閉じる必要があります。

Example 1:

  Input: s = "()"
  Output: true

Example 2:

  Input: s = "()[]{}"
  Output: true

Example 3:

  Input: s = "(]"
  Output: false

Example 4:

  Input: s = "([)]"
  Output: false

Example 5:

  Input: s = "{[]}"
  Output: true

考え方

  1. stack配列と辞書(map)を用意する。
  2. mapには対応する記号を入力
  3. 文字列を一文字ずつ見ていき、括弧の始まりならstackに追加し、閉じ括弧ならstackの直近のものを取り出して合っているかどうか確認。

説明

  1. stackとdict(map)を定義する。
  2. dict = {"]":"[", "}":"{", ")":"("}
  3. for文で文字を一文字ずつみていきます。
  • 解答コード
class Solution:
    def isValid(self, s):
        stack = []
        dict = {"]":"[", "}":"{", ")":"("}
        for char in s:
            if char in dict.values():
                stack.append(char)
            elif char in dict.keys():
                if stack == [] or dict[char] != stack.pop():
                    return False
            else:
                return False
        return stack == []


​ if char in dict.values(): で括弧始まりかどうか

​ elif char in dict.keys():  で括弧終わりかどうか

​ popで最新のstackの文字を取得

​ appendでstackに代入です。

  • Goでも書いてみます!
  func isValid(s string) bool {
    stack := make([]rune, 0)
    m := map[rune]rune{
        ')': '(',
        ']': '[',
        '}': '{',
    }
    for _, c := range s {
        switch c {
        case '(', '{', '[':
            stack = append(stack, c)
        case ')', '}', ']':
            if len(stack) == 0 || stack[len(stack)-1] != m[c] {
                return false
            }
            stack = stack[:len(stack)-1]
        }
    }

    return len(stack) == 0
  }

こちらのコードは少し難しいですが、Goで文字列を一文字ずつ見るためにこのコードになりました。

​ for _, c := range s のループ処理では文字列stringsを一文字ずつ読み取ります。その時cはrune型になるのでmapやスタックもrune型で定義しました。

せっかくGolang書いてるからswitich文で処理を書きました。

  • 自分メモ(Go)

文字列を一文字ずつ見るとrune

スライスにappend(固定長でないのでok)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SOLID原則を理解するためにGo言語で書いてみた

SOLID原則について

SOLID原則とは

  • SRP(単一責任の原則)
  • OCP(オープン・クローズドの原則)
  • LSP(リスコフの置換原則)
  • ISP(インターフェース分離の原則)
  • DIP(依存関係逆転の原則)

の頭文字を取ったものである。

なぜSOLID原則?

SOLIDを適用する理由として、

  • 変更に強くなる
  • 理解しやすくなる
  • 多くのソフトウェアシステムで利用できること

が挙げられます。
以下から、各原則の説明、コードについて触れていきます。

SOLIDの各原則について

SRP(単一責任の原則)

説明

1つのモジュールやクラス、関数などを変更する際に、理由が複数あってはいけないという原則
理由としては以下のような事象が起きることを防ぐため

  • 複数の人が一つのソースファイルを変更した際に、マージやコンフリクトが発生
  • 変更した内容が予期しないところに影響を受ける

コード

悪い例

一つのインタフェースで従業員の管理、従業員のデータの保存と複数の責務を負っている。

type EmployeeWorkManage interface {
    calculatePay()
    reportHours()
    saveEmployee()
}

改善後

従業員の管理、従業員のデータの保存のインターフェースを分けて作成して、責務をそれぞれ1つになるようにする。

type EmployeeWorkManage interface {
    calculatePay()
    reportHours()
}

type EmployeeDataManage interface {
    saveEmployee()
}

OCP(オープン・クローズドの原則)

説明

ソフトウェアの拡張に対して開いていて、修正に対して閉じてなければならないという原則
そうすることで変更の影響を受けずにシステムを拡張できる。

コード

Animalというインターフェイスを作成して、それに依存した形で、Dog型やCat型のメソッドを作成することによって、mainの処理ではDog型やCat型を気にせずに、barkメソッドを実行できる。
また新しくBirdを作りたい場合でも、Animalのインターフェースに依存した作りにすることによって追加だけで済む。

package main
import(
    "fmt"
)

type Animal interface {
    bark()
    eat()
}

type Dog struct {}

type Cat struct {}

func (d Dog) bark(){
    fmt.Println("ワンワン")
}

func (d Dog) eat(){
    fmt.Println("バクバク")
}

func (c Cat) bark(){
    fmt.Println("にゃー")
}

func (c Cat) eat(){
    fmt.Println("ムシャムシャ")
}

func main(){
    dog := Dog{}
    cat := Cat{}

    animals := []Animal{dog, cat}

    for _, animal := range animals {
        animal.bark()
    }

}

LSP(リスコフの置換原則)

説明

S型のオブジェクト :o1
T型のオブジェクト: o2
がある時に、Tを使って定義されたプログラムPに対して、o2の代わりに、o1を使ってもPの振る舞いが変わらない場合、SはTの派生型であるという原則

コード

Goには継承がないため、リスコフの置換原則に違反することがなく意識されない(?)

ISP(インターフェース分離の原則)

説明

不要なインターフェースに依存することを強制してはいけないという原則
関連のあるインターフェースだけをグループ化、利用しないメソッドの依存を失くす。

コード

悪い例

以下のようなAnimalInterfaceから人間型を作ろうとすると、使用しないflyメソッドまで記述をしないといけなくなる。

type AnimalInterface interface {
    fly()
    run()
    swim()
}

改善後

鳥だったらBirdInterface、人間だったらHumanInterfaceとインターフェースを分けるようにする。
そうすることによって不要なメソッドを記述せずに済む。

type BirdInterface interface {
    fly()
}

type HumanInterface interface {
    run()
    swim()
}

type Bird struct {}
type Human struct{}

func (b Bird) fly(){
    fmt.Println("飛びます!!")
}

func (h Human) run(){
    fmt.Println("走るぞ〜")
}

func (h Human) swim(){
    fmt.Println("泳ぎます〜")
}

func main(){
    bird := Bird{}
    human := Human{}

    bird.fly()
    human.run()
}

DIP(依存関係逆転の原則)

説明

頻繁に変更されている具象モジュール(関数の実装が書かれているモジュール)に依存してはいけない原則
変更しやすい具象への依存を避け、安定した抽象インターフェースに依存する。
Abstract Factoryパターンを利用して、抽象インターフェイスを参照するようにする。

コード

Abstract Factoryに依存することによって、依存先が図のようなイメージになり、DBかテキストどちらかを気にせずに、ユーザのデータを取得できるようになる。

Untitled Diagram.png

package main
import(
    "fmt"
)

type User struct {
    id int
    name string
}

type AbstractFactory interface {
    getData() User
}

type DbManage struct {}

func (db DbManage) getData() User {
    return User{1, "DB TARO"}
}

type TextManage struct {}

func (text TextManage) getData() User {
    return User{2, "TEXT JIRO"}
}

func getUserData(manageType string) User {
    var manageFactry AbstractFactory
    switch manageType {
    case "DB":
        manageFactry = DbManage{}
        return manageFactry.getData()
    case "TEXT":
        manageFactry = TextManage{}
        return manageFactry.getData()
    default:
        return User{3, "名無し"}
    }
}

func main(){
    user := getUserData("DB")
    fmt.Println(user.id, user.name)
}



参考

https://labs.septeni.co.jp/entry/2017/02/21/164127
https://maroyaka.hateblo.jp/entry/2017/05/22/165355
https://qiita.com/shunp/items/646c86bb3cc149f7cff9
https://golangvedu.wordpress.com/2017/01/31/golang-design-pattern-abstract-factory-and-factory-method/

最後に

なんとなくですが、SOLID原則について分かったような気がします。
質問やご指摘がございましたら、コメントに書いていただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go言語のTwitter APIで定期的にツイートする

用意するもの

・MAC(PC)
・AWS Lambda
・Twitter API
・Twitterアカウント

やったこと

1.Twitter API申請

下記URLからTwitter API申請をします。
https://developer.twitter.com/ja/docs

API key & secretとAccess token & secretを取得します。

2.Go言語で書く

Twiiter認証用のソースコードを書きます。
別にファイルは分けなくてもいいです。

keys.go
package keys

import 
(
    //Twitter APIに必要なimportになります。なければインストールしましょう。   
    "github.com/ChimeraCoder/anaconda"
)

func GetTwitterApi() *anaconda.TwitterApi {
    anaconda.SetConsumerKey("API Key")
    anaconda.SetConsumerSecret("API secret Key")
    api := anaconda.NewTwitterApi("token", "token secret")
    return api
}

ツイート本文のソースコードを書きます。
これも別にファイル分けなくてもできます。
日付とテキストをツイートするようにしています。

text.go
package text

import (
    "fmt"
    "time"
)

func TextTweet() string {
    //tweetする文章を書くよ
    tweetText := "test"

    d := time.Now().Day()
    m := time.Now().Month()

    //ツイートする文章を格納する。
    TweetContent := tweetText
    TweetOfToday := fmt.Sprintf("【%d月%d日】\n %s", m, d, TweetContent)
    return TweetOfToday
}

実際にツイートするソースを書きます。

main.go
package main

import (
    "fmt"
    . "fmt"

    . "./keys"
    . "./text"
)
func main(){
    api := GetTwitterApi()
    text := TextTweet()

    tweet, err := api.PostTweet(text, nil)
    if err != nil {
       panic(err)
    }
     Print(tweet.Text)

     fmt.Println("Finish!")
}

ちなみにフォルダ構成は以下です。

autoTweet
  ∟main.go
 ∟keys
   ∟keys.go
  ∟text
   ∟text.go

3.AWS Lambdaで実行させる

AWS LambdaにGoソースコードをzipファイルにしてアップロードします。
↓がとても参考になりました。
https://dev.classmethod.jp/articles/aws-lambda-supports-go/

AWS Lambdaにアップロードして実行するにはバイナリファイルが必要です。
私は1つのファイル(main.go)にまとめてバイナリファイルにしました。
バイナリファイル作成コマンドは↓です。zipにするのはバイナリファイルのみで大丈夫です。

#GOOS=linux GOARCH=amd64 go build main.go

バイナリファイルが作成がエラーになった場合は、下記試してみてください。

#go get -u golang.org/x/sys/unix
#set GOOS=linux
#set GOARCH=amd64
#set CGO_ENABLED=0

Lambdaでテストしてみて実行エラーにならなかったらツイッター見にいきましょう!
ツイートされているはずです!

4.CloudWatchEventsでLambdaを定期実行する。

CloudWatchEventsのCron式でLambdaを定期実行させます。
Cron式は2ヶ月に一度とか、設定次第で好きな時間に実行できます。
参考URL:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/services-cloudwatchevents-expressions.html

参考に毎日12時に実行するcron式記載しておきます。 (UTCのため-9時間になります)

crons式:
00 3 * * ? *

5.ツイート確認

設定した時間になってツイートされてたらOK!

かなり雑に書いてしまいましたが、誰かの参考になれば幸いです。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

gRPCに入門する~gRPC-Webで実装もしてみる~

はじめに

タイトルにもある通りgRPCに入門してみたので実際に動かしてみようと思います。

この記事は、僕がgRPCに入門して、「gRPCって何?」から「gRPCちょっとわかってきたな」になるまでにやったことをまとめた(説明した)ものになっているので、同じような状況の方におすすめです。

この記事の内容

  • gRPCについて軽く説明
  • gRPC-Webについて軽く説明
  • Go × TypeScript × gRPC-Webで実際に動かしてみる

入門したでなので、訂正や補足などありましたら、是非コメントお願いします!🙇‍♂️

gRPC とは

RPC とは

gRPCとはなんぞや、という話に行く前にRPCとはなんでしょうか。

RPCはRemote Procedure Callの略で、「遠隔手続き呼び出し」とも呼ばれます。
簡単に説明すると、他サーバー上の関数を呼び出し、実行することを可能にする手法です。
また、同じRPCの仕様に準拠していれば、呼び出される関数は別の言語で実装されていてもかまいません。

そして、呼び出しの規約はインタフェース記述言語(IDL)で記述されます。
関数のインターフェースを記述し、コンパイルすることでそのファイルから言語に合わせたコードを生成します。

Protocol Buffers とは

Protocol Bufferは構造化されたデータをシリアライズするデータフォーマットで、gRPCではデフォルトフォーマットとなっています。Googleによって開発されています。

gRPCとは

以上のことを踏まえてgRPCについて簡単に説明します。

gRPCとは、Googleが開発したOSSのRPCフレームワークです。

特徴

  • Protocol Buffersを利用して高速かつ低容量での通信を実現。
    • 送信データをシリアライズしてバイナリに変換しているため
  • 多言語に対応
    • C++, Java, Go, Node.js, Ruby, PHP, Python 等
  • HTTP/2 でデータを送受信
  • IDLからサーバーとクライアントのコードを自動生成
    • サーバーとクライアントは異なる言語でも可能

開発の流れ

  1. .protoファイルを作成する
  2. .protoファイルをコンパイルしてサーバー、クライアントのコードを自動生成する
  3. サーバー、クライアントを実装する

参考

gRPC-Web とは

gRPC-WebによってgRPCサーバーをブラウザから利用できるようになります

gRPC-Webを用いない場合、右図のように間にREST APIサーバーを挟んでgRPCを呼び出していますが、gRPC-Webを利用する場合は、左図のようにブラウザから直接gRPCを利用できます。
image.png
(画像は公式より引用)

しかし、実際には下図のようにgRPC-Web対応のプロキシが必要になります。
なお、公式ではenvoyが推奨されています。
image.png
(画像はhttps://blog.envoyproxy.io/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880 より引用)

参考

Go × TypeScript × gRPC-Web ハンズオン

では、実際にgRPCを使ってみましょう。
今回はgRPC-Webを利用して、ブラウザ上で「名前」を入力すると「Hello 名前 !」と返すようにしてみたいと思います。

なお、クライアントはTypeScript、サーバーはGoで実装、プロキシはenvoyを利用しています。

完成形はこんな感じです。
画面収録 2020-11-22 11.51.11.mov.gif

また、ソースコードはこちらに置いてます↓
Le0tk0k/grpc-sample - GitHub

環境

Mac OS Catalina
Node.js v12.18.4
npm 6.14.9
yarn 1.22.10
Go 1.15

準備

以下のパッケージをインストールします

  • protobuf
  • protoc-gen-grpc-web
  • protoc-gen-go
$ brew install protobuf protoc-gen-grpc-web protoc-gen-go

.protoファイルを作成する

.protoファイルの書き方はhttps://knowledge.sakura.ad.jp/24059/# が参考になります。

まずはサービスのインターフェースを定義します。
HelloServiceというserviceはHelloRequestを受け取りHelloResponseを返すSayHelloというAPIを定義しています。

proto/hello.proto
syntax = "proto3";

service HelloService {
    rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}

クライアントのベース作成

定義ファイルからコードを生成する前にクライアントのベースを作成します。
create-react-appを使用します。
続けて、パッケージもインストールします。

$ pwd
  /grpc-sample 
$ npx create-react-app client --template typescript
$ cd client
$ yarn add grpc-web google-protobuf

定義ファイルをコンパイルしてコードを生成

$ pwd
  /grpc-sample
$ mkdir -p server/hello
$ mkdir -p client/src/hello
# サーバー用のコードを生成
$ protoc --go_out=plugins=grpc:server/hello -I=proto proto/hello.proto
$ tree server/hello   
  server/hello
  └── hello.pb.go
# クライアント用のコードを生成
$ protoc \  
--grpc-web_out=import_style=typescript,mode=grpcwebtext:client/src/hello \
--js_out=import_style=commonjs:client/src/hello -I=proto proto/hello.proto
$ tree client/src/hello
  client/src/hello
  ├── HelloServiceClientPb.ts
  ├── hello_pb.d.ts
  └── hello_pb.js

クライアント側の実装

client/src/App.tsx
import React, { useState } from 'react';
import './App.css';
import {HelloRequest} from './hello/hello_pb';
import {HelloServiceClient} from './hello/HelloServiceClientPb';

function App() {
  const [name, setName] = useState('');
  const [message, setMessage] = useState('');

  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value);
  };

  const onClick = async () => {
    const request = new HelloRequest();
    request.setName(name);
    const client = new HelloServiceClient("http://localhost:8080");
    const response = await client.sayHello(request, {});
    setMessage(response.getMessage());
  };

  return (
    <div className="App">
      <input 
        type="text"
        value={name}
        onChange={onChange}
      />
      <button onClick={onClick}>Send</button>
      <p>{message}</p>
    </div>
  );
}

export default App;

この状態でyarn startするとエラーが出るので、
hello_pb.jsの先頭に/* eslint-disable */を記述します。

サーバー側の実装

go.modは生成しておいてください。

server/main.go
package main

import (
    "context"
    "log"
    "net"

    pb "github.com/Le0tk0k/server/hello"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
)

const (
    port = ":9090"
)

type server struct{}

func (s *server) SayHello(ctx context.Context, r *pb.HelloRequest) (*pb.HelloResponse, error) {
    log.Printf("Recieved : %s", r.GetName())
    return &pb.HelloResponse{Message: "Hello " + r.GetName() + "!"}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    s := grpc.NewServer()
    pb.RegisterHelloServiceServer(s, &server{})
    reflection.Register(s)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %c", err)
    }
}

プロキシの設定

envoyの設定ファイルを作成します。

proxy/envoy.yaml
admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  cluster: greeter_service
                  max_grpc_timeout: 0s
              cors:
                allow_origin_string_match:
                  - prefix: "*"
                allow_methods: GET, PUT, DELETE, POST, OPTIONS
                allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
                max_age: "1728000"
                expose_headers: custom-header-1,grpc-status,grpc-message
          http_filters:
          - name: envoy.filters.http.grpc_web
          - name: envoy.filters.http.cors
          - name: envoy.filters.http.router
  clusters:
  - name: greeter_service
    connect_timeout: 0.25s
    type: logical_dns
    http2_protocol_options: {}
    lb_policy: round_robin
    load_assignment:
      cluster_name: cluster_0
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: host.docker.internal
                    port_value: 9090

envoyの環境構築はDockerで行います。

proxy/Dockerfile
FROM envoyproxy/envoy:v1.15.0
COPY ./envoy.yaml /etc/envoy/envoy.yaml
CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml
EXPOSE 8080
docker-compose.yml
version: "3"
services:
  envoy:
    build:
      context:  ./proxy
    ports:
      - "8080:8080"

これで実装は以上です!

実行してみる

$ yarn start
$ go run main.go
$ docker-compose up -d

で http://localhost:3000/ にアクセスしてください。

参考

おわりに

 gRPC?な状態からなんとなくわかるぐらいにはなれたので、また勉強していきたいと思います!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

現場で使えるゴルーチン(並列制御)

func main() {
    ch := make(chan struct{}, 10)
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        ch <- struct{}{}
        wg.Add(1)
        go func(i int) {
            defer func() {
                <-ch
                wg.Done()
            }()

            fmt.Println(i)
        }(i)
    }
    wg.Wait()
}

https://play.golang.org/p/Cry94fFpeFH

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GOでPostgresqlへ接続する

DockerでPostgreを起動する

docker-compose.yml
version: "3"
services:
  postgres:
    image: postgres
    container_name: postgres
    ports:
      - 5432:5432
    environment:
      - POSTGRES_USER=root
      - POSTGRES_PASSWORD=password
    tty: true
    restart: always
    user: root
    volumes:
      - ./init:/docker-entrypoint-initdb.d
      - /etc/localtime:/etc/localtime:ro
  pgweb:
    image: sosedoff/pgweb
    container_name: pgweb
    ports: 
      - "8081:8081"
    environment:
      - DATABASE_URL=postgres://root:password@postgres:5432/testdb?sslmode=disable
    links: 
      - postgres:postgres
    restart: always
    depends_on:
      - postgres

起動

docker-compose up -d

Goから接続

main.go
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

const (
    // Initialize connection constants.
    HOST     = "127.0.0.1"
    DATABASE = "testdb"
    USER     = "root"
    PASSWORD = "password"
)

func checkError(err error) {
    if err != nil {
        panic(err)
    }
}

func main() {
    // Initialize connection string.
    var connectionString string = fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", HOST, USER, PASSWORD, DATABASE)

    // Initialize connection object.
    db, err := sql.Open("postgres", connectionString)
    checkError(err)

    err = db.Ping()
    checkError(err)
    fmt.Println("Successfully created connection to database")

    // Drop previous table of same name if one exists.
    _, err = db.Exec("DROP TABLE IF EXISTS inventory;")
    checkError(err)
    fmt.Println("Finished dropping table (if existed)")

    // Create table.
    _, err = db.Exec("CREATE TABLE inventory (id serial PRIMARY KEY, name VARCHAR(50), quantity INTEGER);")
    checkError(err)
    fmt.Println("Finished creating table")

    // Insert some data into table.
    sql_statement := "INSERT INTO inventory (name, quantity) VALUES ($1, $2);"
    _, err = db.Exec(sql_statement, "banana", 150)
    checkError(err)
    _, err = db.Exec(sql_statement, "orange", 154)
    checkError(err)
    _, err = db.Exec(sql_statement, "apple", 100)
    checkError(err)
    fmt.Println("Inserted 3 rows of data")
}
go run main.go

psqlで接続

シェルから接続

psql -h localhost -U root -d postgres -p 5432

DB一覧表示

\l

対象DBへ接続

\c testdb

カレントDBを確認

select current_database();

データが入っているか確認

testdb=# select * from inventory;
 id |  name  | quantity 
----+--------+----------
  1 | banana |      150
  2 | orange |      154
  3 | apple  |      100

参考

https://qiita.com/hiro9/items/e6e41ec822a7077c3568
https://docs.microsoft.com/ja-jp/azure/postgresql/connect-go

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go言語の特徴

概要

  • Gocci.meと言うサービスをGo言語で開発しており、そのGo言語の持つ特徴をまとめました

言語設計と文法

シンプル

Go言語はいろいろな書き方が存在するわけではなく、ある程度書き方が決まっているので、シンプルに実装することができます。
比較的昨日の割には言語仕様を理解しやすくなっています。

コンパイル言語

コンパイル言語とは実行をする前に一括で全てのコードを機械語もしくは中間言語にコンパイル(翻訳)する言語のことです。
コンパイル言語は記述方法が厳密と言う特徴がありますが、一括で機械語に変換してコンピュータに処理させるため、処理が高速であると言う特徴を持ちます。
Go言語はコンパイル速度も早いと言われています。

静的型付け

Go言語ではプログラムを書く際に予め型を指定しなければいけません
静的型付けは事前にコンパイルを行うことで、プログラムの実行時には型の生合成チェックをする必要がなく、処理が高速になります。
また、コンパイル時に型のチェックを行うため、型の整合エラーをチェックできます
JavaやC言語がこの特徴を持っています。

対してプログラムを書く際に型付けを行わない動的型付け言語が存在します。
JavaScriptやRubyやPythonなどが動的型付け言語になります。
これらは処理は高速ではありませんが、プログラムの記述量が少なく、文甫の学習コストが低いため、直感的にコードを書くことができます。

並行プログラミング

ゴールーチン

処理を仮想スレッドで起動する機能のことで、軽量なスレッドのイメージです。
goキーワードをつけて関数を呼び出すことで実現できます。

func main() {
  go f()  // ゴールーチンの呼び出し
}
func f() {
  // some task
}

ゴールーチンでは関数に戻り値を設定することができません。
ゴールーチンでは処理が完了されると破棄されます。

チャネル

ゴールーチンのみでは作業中か破棄されたのかを検知することができないため、意図しない挙動が発生した時にエラーハンドリングなどができません。
また、戻り値がないので、作業の結果として加工した値を受け取ることもできません。
そこでチャネルと言う機能によって、ゴールーチン間のデータのやりとりを可能にします
チャネルの受信を記述することで、値が送信されるまで待ってくれます
チャネルはバッファを持たせることもでき、作成時にバッファを指定すると、チャネルが持てるデータの個数が決まります。(デフォルトは0)
バッファを超えて値を送信すると、送信ブロッキングが発生します。

豊富な標準ライブラリ

Go言語には標準ライブラリが豊富に揃っています。

シングルバイナリ・クロスコンパイル

Go言語では異なるOSやアーキテクチャ向けのバイナリを作ることができます。
下記のように環境変数のGOOSとGOARCHを指定することで実現可能です

# Windows(32bit)向け
$ GOOS=windows GOARCH=386 go build

# Linux(64bit)向け
$ GOOS=linux GOARCH=amd64 go build

Go言語で書かれたプログラムは基本的には単体で実行可能なシングルバイナリとして生成されます。
一旦コンパイルしてしまえばLL言語(短い記述で処理を実現できる言語)などで必要なランタイムや依存関係の管理が必要なくなり、動作環境を用意しなくていいと言う特徴があります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCodeに毎日挑戦してみた 14.Longest Common Prefix (Python、Go)

はじめに

無料英単語サイトE-tanを運営中の@ishishowです。

プログラマとしての能力を上げるために毎日leetcodeに取り組み、自分なりの解き方を挙げていきたいと思います。

Leetcodeとは

leetcode.com
ソフトウェア開発職のコーディング面接の練習といえばこれらしいです。
合計1500問以上のコーデイング問題が投稿されていて、実際の面接でも同じ問題が出されることは多いらしいとのことです。

Go言語入門+アルゴリズム脳の強化のためにGolangとPythonで解いていこうと思います。(Pythonは弱弱だが経験あり)

5問目(問題14)

14.Longest Common Prefix

  • 問題内容(日本語訳)

文字列の配列の中から最も長い共通のプレフィックス文字列を見つける関数を記述します。

共通のプレフィックスがない場合は、空の文字列を返します""

Example 1:

Input: strs = ["flower","flow","flight"]
Output: "fl"

Example 2:

Input: strs = ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.

考え方

  1. 配列の中から一番短い単語を抽出
  2. その単語を一文字ずつループ回す
  3. ループの中で出現単語をすべてその文字を確認して違ったらreturn,違くなかったら進める

説明

  1. minメソッドを使うと配列の中の一番文字数が少ない要素を取得できます。
  2. for文でもなんでもいいです。
  3. returnはスライスを使います。array[:number]で指定の範囲で切り取れます。
  • 解答コード
def longestCommonPrefix(self, strs):
    """
    :type strs: List[str]
    :rtype: str
    """
    if not strs:
        return ""
    shortest = min(strs,key=len)
    for i, ch in enumerate(shortest):
        for other in strs:
            if other[i] != ch:
                return shortest[:i]
    return shortest 
  • Goでも書いてみます!
func longestCommonPrefix(strs []string) string {
    if len(strs) == 0 {
        return ""
    }
    max := len(strs[0])

    for i := 0; i < max; i++ {
        b := strs[0][i]
        for _, str := range strs[1:] {
            if i == len(str) || b != str[i] {
                return strs[0][:i]
            }
        }
    }
    return strs[0]
}

GoとPythonの実行時間

左から、RunTime, Memory, 言語です。
キャプチャ.PNG

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む