- 投稿日:2020-11-22T23:17:14+09:00
LeetCodeに毎日挑戦してみた 20. Valid Parentheses(Python、Go)
はじめに
無料英単語サイトE-tanを運営中の@ishishowです。
プログラマとしての能力を上げるために毎日leetcodeに取り組み、自分なりの解き方を挙げていきたいと思います。
Leetcodeとは
leetcode.com
ソフトウェア開発職のコーディング面接の練習といえばこれらしいです。
合計1500問以上のコーデイング問題が投稿されていて、実際の面接でも同じ問題が出されることは多いらしいとのことです。Go言語入門+アルゴリズム脳の強化のためにGolangとPythonで解いていこうと思います。(Pythonは弱弱だが経験あり)
6問目(問題20)
20. Valid Parentheses
- 問題内容(日本語訳)
文字列を考える
s
だけで文字を含む'('
、')'
、'{'
、'}'
、'['
と']'
、入力文字列が有効であるかどうかを決定。入力文字列は、次の場合に有効です。
- 開いたブラケットは、同じタイプのブラケットで閉じる必要があります。
- 開いたブラケットは正しい順序で閉じる必要があります。
Example 1:
Input: s = "()" Output: trueExample 2:
Input: s = "()[]{}" Output: trueExample 3:
Input: s = "(]" Output: falseExample 4:
Input: s = "([)]" Output: falseExample 5:
Input: s = "{[]}" Output: true考え方
- stack配列と辞書(map)を用意する。
- mapには対応する記号を入力
- 文字列を一文字ずつ見ていき、括弧の始まりならstackに追加し、閉じ括弧ならstackの直近のものを取り出して合っているかどうか確認。
説明
- stackとdict(map)を定義する。
- dict = {"]":"[", "}":"{", ")":"("}
- 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)
- 投稿日:2020-11-22T19:49:56+09:00
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かテキストどちらかを気にせずに、ユーザのデータを取得できるようになる。
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原則について分かったような気がします。
質問やご指摘がございましたら、コメントに書いていただけると幸いです。
- 投稿日:2020-11-22T17:20:50+09:00
Go言語のTwitter APIで定期的にツイートする
用意するもの
・MAC(PC)
・AWS Lambda
・Twitter API
・Twitterアカウントやったこと
1.Twitter API申請
下記URLからTwitter API申請をします。
https://developer.twitter.com/ja/docsAPI key & secretとAccess token & secretを取得します。
2.Go言語で書く
Twiiter認証用のソースコードを書きます。
別にファイルは分けなくてもいいです。keys.gopackage 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.gopackage 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.gopackage 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.go3.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=0Lambdaでテストしてみて実行エラーにならなかったらツイッター見にいきましょう!
ツイートされているはずです!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!
かなり雑に書いてしまいましたが、誰かの参考になれば幸いです。。。
- 投稿日:2020-11-22T16:33:16+09:00
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からサーバーとクライアントのコードを自動生成
- サーバーとクライアントは異なる言語でも可能
開発の流れ
.proto
ファイルを作成する.proto
ファイルをコンパイルしてサーバー、クライアントのコードを自動生成する- サーバー、クライアントを実装する
参考
gRPC-Web とは
gRPC-WebによってgRPCサーバーをブラウザから利用できるようになります
gRPC-Webを用いない場合、右図のように間にREST APIサーバーを挟んでgRPCを呼び出していますが、gRPC-Webを利用する場合は、左図のようにブラウザから直接gRPCを利用できます。
(画像は公式より引用)しかし、実際には下図のようにgRPC-Web対応のプロキシが必要になります。
なお、公式ではenvoyが推奨されています。
(画像は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を利用しています。
環境
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.protosyntax = "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.tsximport 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.gopackage 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.yamladmin: 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: 9090envoyの環境構築はDockerで行います。
proxy/DockerfileFROM envoyproxy/envoy:v1.15.0 COPY ./envoy.yaml /etc/envoy/envoy.yaml CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml EXPOSE 8080docker-compose.ymlversion: "3" services: envoy: build: context: ./proxy ports: - "8080:8080"これで実装は以上です!
実行してみる
$ yarn start $ go run main.go $ docker-compose up -dで http://localhost:3000/ にアクセスしてください。
参考
- https://qiita.com/y-imai/items/5692559a6e17844e4e75#
- https://qiita.com/otanu/items/98d553d4b685a8419952#
- https://zenn.dev/t_horikoshi/articles/dfc2a02c7eb30f7f0819
おわりに
gRPC?な状態からなんとなくわかるぐらいにはなれたので、また勉強していきたいと思います!
- 投稿日:2020-11-22T13:18:38+09:00
現場で使えるゴルーチン(並列制御)
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() }
- 投稿日:2020-11-22T12:47:40+09:00
GOでPostgresqlへ接続する
DockerでPostgreを起動する
docker-compose.ymlversion: "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 -dGoから接続
main.gopackage 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.gopsqlで接続
シェルから接続
psql -h localhost -U root -d postgres -p 5432DB一覧表示
\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
- 投稿日:2020-11-22T04:48:28+09:00
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 buildGo言語で書かれたプログラムは基本的には単体で実行可能なシングルバイナリとして生成されます。
一旦コンパイルしてしまえばLL言語(短い記述で処理を実現できる言語)などで必要なランタイムや依存関係の管理が必要なくなり、動作環境を用意しなくていいと言う特徴があります。
- 投稿日:2020-11-22T01:06:38+09:00
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.考え方
- 配列の中から一番短い単語を抽出
- その単語を一文字ずつループ回す
- ループの中で出現単語をすべてその文字を確認して違ったらreturn,違くなかったら進める
説明
- minメソッドを使うと配列の中の一番文字数が少ない要素を取得できます。
- for文でもなんでもいいです。
- 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の実行時間