20200325のGoに関する記事は4件です。

Goでのint型変数の絶対値出力

はじめに

Go言語でPaizaを解いていた時に絶対値の出力で詰まったためメモ。
初学者のため誤り等ありましたらご指摘ください。
Goバージョン:1.13.8

Goでの絶対値の出力方法

下記のようにint型の変数aをmath.Absを使用し絶対値を出力しようとした場合、エラーとなった。

エラーとなったコード

package main

import (
    "fmt"
    "math"
)

func main() {
    var a int
    a = -1
    fmt.Println(math.Abs(a))
}
cannot use a (type int) as type float64 in argument to math.Abs

どうやらmath.Absではfloat64の型しか許容していないよう。

正常に動作したコード

int型の変数aをfloat64型にキャスト変換した上でmath.Absにて絶対値を取得。その値を変数bに設定。
整数で出力するために変数bをint型に変換して出力。

package main

import (
    "fmt"
    "math"
)

func main() {
    var a int
    var b float64
    a = -1
    b = math.Abs(float64(a)) // float64型にキャスト変換し、変数bに絶対値を設定
    fmt.Printf("%d", int(b)) // 整数で出力するためにint型に変換し出力。
}

出力結果

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

Golangでのint型変数の絶対値取得

はじめに

Go言語でPaizaを解いていた時に絶対値の取得で詰まったためメモ。
初学者のため誤り等ありましたらご指摘ください。
Goバージョン:1.13.8

Goでの絶対値の取得方法

下記のようにint型の変数aをmath.Absを使用し、絶対値を取得しようとした場合、エラーとなる。

エラーとなったコード

package main

import (
    "fmt"
    "math"
)

func main() {
    var a int
    a = -1
    fmt.Println(math.Abs(a))
}
cannot use a (type int) as type float64 in argument to math.Abs

どうやらmath.Absではfloat64の型しか許容していないよう。

正常に動作したコード

下記のようにint型の変数aをfloat64にキャスト変換すると正常に出力された。

package main

import (
    "fmt"
    "math"
)

func main() {
    var a int
    a = -1
    fmt.Println(math.Abs(float64(a)))
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Goでのint型変数の絶対値取得

はじめに

Go言語でPaizaを解いていた時に絶対値の取得で詰まったためメモ。
初学者のため誤り等ありましたらご指摘ください。
Goバージョン:1.13.8

Goでの絶対値の取得方法

下記のようにint型の変数aをmath.Absを使用し、絶対値を取得しようとした場合、エラーとなる。

エラーとなったコード

package main

import (
    "fmt"
    "math"
)

func main() {
    var a int
    a = -1
    fmt.Println(math.Abs(a))
}
cannot use a (type int) as type float64 in argument to math.Abs

どうやらmath.Absではfloat64の型しか許容していないよう。

正常に動作したコード

下記のようにint型の変数aをfloat64にキャスト変換すると正常に出力された。

package main

import (
    "fmt"
    "math"
)

func main() {
    var a int
    a = -1
    fmt.Println(math.Abs(float64(a)))
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golangで、デザインパターン「Bridge」を学ぶ

GoFのデザインパターンを学習する素材として、書籍「増補改訂版Java言語で学ぶデザインパターン入門」が参考になるみたいですね。
取り上げられている実例は、JAVAベースのため、Pythonで同等のプラクティスに挑んだことがありました。
Qiita記事: "Pythonで、デザインパターン「Bridge」を学ぶ"

今回は、Pythonで実装した”Bridge”のサンプルアプリをGolangで実装し直してみました。

■ Bridge(ブリッジ・パターン)

Bridgeパターン(ブリッジ・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。 「橋渡し」のクラスを用意することによって、クラスを複数の方向に拡張させることを目的とする。

UML class and sequence diagram

W3sDesign_Bridge_Design_Pattern_UML.jpg

UML class diagram

bridge.png
(以上、ウィキペディア(Wikipedia)より引用)

□ 備忘録

Bridgeパターンは、機能のクラス階層実装のクラス階層を橋渡しするらしいです。

(1) 機能のクラス階層とは?

あるクラスに対して、新しい機能を追加したい場合、新しくサブクラスを定義した上で、メソッドを実装します。
既存のスーパークラスと、新たに定義したサブクラスの関係が、"機能のクラス階層"になります。
一般的には、以下のような関係を想定します。

  • スーパークラスは基本的な機能を持っている
  • サブクラスで新しい機能を追加する

(2) 実装のクラス階層とは?

新しい実装を追加したい場合、抽象クラスから派生した具体的なサブクラスを定義した上で、メソッドを実装します。
既存の抽象クラスと、新たに派生した具体的なサブクラスの関係が、"実装のクラス階層"になります。
一般的には、以下のような関係を想定します。

  • 抽象クラスでは、抽象メソッドによってインタフェースを規定している
  • 派生したサブクラスは具象メソッドによってそのインタフェースを実装する

■ "Bridge"のサンプルプログラム

実際に、Bridgeパターンを活用したサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。
機能のクラス階層実装のクラス階層を橋渡しを想定したサンプルになります。

  • DisplayFuncと、DisplayStringImplの橋渡しを経て、文字列を表示する
  • DisplayCountFuncと、DisplayStringImplの橋渡しを経て、文字列を表示する
  • DisplayCountFuncと、DisplayStringImplの橋渡しを経て、文字列を表示する
  • DisplayRandomFuncと、DisplayStringImplの橋渡しを経て、文字列を5回繰り返して表示する
  • DisplayRandomFuncと、DisplayStringImplの橋渡しを経て、文字列をランダム回数繰り返して表示する
  • DisplayFuncと、DisplayTextfileImplの橋渡しを経て、テキストファイルの内容を表示する
$ go run Main.go 
+-----------+
|Hello Japan|
+-----------+

+-----------+
|Hello Japan|
+-----------+

+--------------+
|Hello Universe|
+--------------+

+--------------+
|Hello Universe|
|Hello Universe|
|Hello Universe|
|Hello Universe|
|Hello Universe|
+--------------+

+--------------+
|Hello Universe|
|Hello Universe|
+--------------+

aaa
bbb
ccc
ddd
eee
fff
ggg

サンプルプログラムを動かしただけだと、いまいち、何がしたいのかよく分かりませんね。
つづいて、サンプルプログラムの詳細を確認していきます。

■ サンプルプログラムの詳細

Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern_with_golang/tree/master/Bridge

  • ディレクトリ構成
.
├── Main.go
├── bridge
│   ├── display_count_func.go
│   ├── display_func.go
│   ├── display_impl.go
│   ├── display_random_func.go
│   ├── display_string_impl.go
│   └── display_textfile_impl.go
└── test.txt

(1) Abstraction(抽象化)の役

Implement役のメソッドを使って、基本的な機能だけが実装されているクラスです。
サンプルプログラムでは、DisplayFunc構造体が、この役を努めます。

bridge/display_func.go
package bridge

// DisplayFunc is struct
type DisplayFunc struct {
    impl displayImpl
}

// NewDisplayFunc func for initializing DisplayFunc
func NewDisplayFunc(impl displayImpl) *DisplayFunc {
    return &DisplayFunc{
        impl: impl,
    }
}

func (d *DisplayFunc) open() {
    d.impl.rawOpen()
}

func (d *DisplayFunc) printBody() {
    d.impl.rawPrint()
}

func (d *DisplayFunc) close() {
    d.impl.rawClose()
}

//Display  func for displaying string
func (d *DisplayFunc) Display() {
    d.open()
    d.printBody()
    d.close()
}

(2) RefinedAbstraction(改善した抽象化)の役

Abstraction役に対して機能を追加した役です。
サンプルプログラムでは、DisplayCountFunc構造体と、DisplayRandomFunc構造体が、この役を努めます。

bridge/display_count_func.go
package bridge

// DisplayCountFunc is struct
type DisplayCountFunc struct {
    *DisplayFunc
}

// NewDisplayCountFunc func for initializing DisplayCountFunc
func NewDisplayCountFunc(impl displayImpl) *DisplayCountFunc {
    return &DisplayCountFunc{
        DisplayFunc: &DisplayFunc{
            impl: impl,
        },
    }
}

//MultiDisplay  func for displaying string
func (d *DisplayCountFunc) MultiDisplay(times int) {
    d.open()
    for i := 0; i < times; i++ {
        d.printBody()
    }
    d.close()
}
bridge/display_random_func.go
package bridge

import (
    "math/rand"
    "time"
)

// DisplayRandomFunc is struct
type DisplayRandomFunc struct {
    *DisplayFunc
}

// NewDisplayRandomFunc func for initializing DisplayRandomFunc
func NewDisplayRandomFunc(impl displayImpl) *DisplayRandomFunc {
    return &DisplayRandomFunc{
        DisplayFunc: &DisplayFunc{
            impl: impl,
        },
    }
}

//RandomDisplay  func for displaying string
func (d *DisplayRandomFunc) RandomDisplay(times int) {
    d.open()
    rand.Seed(time.Now().UnixNano())
    randomTimes := rand.Intn(times)
    for i := 0; i < randomTimes; i++ {
        d.printBody()
    }
    d.close()
}

(3) Implementor(実装者)の役

Abstraction役のインタフェースを実装するためのメソッドを規定する役です。
サンプルプログラムでは、DisplayImplインタフェースが、この役を努めます。

bridge/display_impl.go
package bridge

type displayImpl interface {
    rawOpen()
    rawPrint()
    rawClose()
}

(4) ConcreteImplementor(具体的な実装者)の役

具体的にImplement役のインタフェースを実装する役です。
サンプルプログラムでは、DisplayStringImpl構造体と、DisplayTextfileImpl構造体が、この役を努めます。

bridge/display_string_impl.go
package bridge

import (
    "fmt"
    "strings"
)

// DisplayStringImpl is struct
type DisplayStringImpl struct {
    str   string
    width int
}

// NewDisplayStringImpl func for initializing DisplayStringImpl
func NewDisplayStringImpl(str string) *DisplayStringImpl {
    return &DisplayStringImpl{
        str:   str,
        width: len(str),
    }
}

func (d *DisplayStringImpl) rawOpen() {
    d.printLine()
}

func (d *DisplayStringImpl) rawPrint() {
    fmt.Printf("|%s|\n", d.str)
}

func (d *DisplayStringImpl) rawClose() {
    d.printLine()
    fmt.Println("")
}

func (d *DisplayStringImpl) printLine() {
    line := strings.Repeat("-", d.width)
    fmt.Printf("+%s+\n", line)
}
bridge/display_textfile_impl.go
package bridge

import (
    "fmt"
    "os"
)

// DisplayTextfileImpl is struct
type DisplayTextfileImpl struct {
    fileName string
    f        *os.File
}

// NewDisplayTextfileImpl func for initializing DisplayTextfileImpl
func NewDisplayTextfileImpl(str string) *DisplayTextfileImpl {
    return &DisplayTextfileImpl{
        fileName: str,
    }
}

func (d *DisplayTextfileImpl) rawOpen() {
    fp, err := os.Open(d.fileName)
    if err != nil {
        panic(err)
    } else {
        d.f = fp
    }
}

func (d *DisplayTextfileImpl) rawPrint() {
    buf := make([]byte, 64)
    _, err := d.f.Read(buf)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s\n", buf)
}

func (d *DisplayTextfileImpl) rawClose() {
    d.f.Close()
}

(5) Client(依頼人)の役

サンプルプログラムでは、startMain関数が、この役を努めます。

Main.go
package main

import (
    "./bridge"
)

func startMain() {
    d1 := bridge.NewDisplayFunc(bridge.NewDisplayStringImpl("Hello Japan"))
    d2 := bridge.NewDisplayCountFunc(bridge.NewDisplayStringImpl("Hello Japan"))
    d3 := bridge.NewDisplayCountFunc(bridge.NewDisplayStringImpl("Hello Universe"))
    d4 := bridge.NewDisplayRandomFunc(bridge.NewDisplayStringImpl("Hello Universe"))
    d5 := bridge.NewDisplayFunc(bridge.NewDisplayTextfileImpl("test.txt"))
    d1.Display()
    d2.Display()
    d3.Display()
    d3.MultiDisplay(5)
    d4.RandomDisplay(5)
    d5.Display()
}

func main() {
    startMain()
}

■ 参考URL

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