こんにちは、ナナオです。

前回に引き続き競プロを実施していきたいと思います。

今回の問題は以下です。

静的メンバ | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】

実装

前回のデフォルト値と同じく、Goには静的メンバのような機能はありません。

ということで、普通に変数を定義してあげます。

package main
import "fmt"
// OrderAlCohol関数に対するデフォルト値設定のためのOptions構造体を定義
type OrderAlCoholOptions struct {
    Amount int
}
type OrderAlCoholOption func(*OrderAlCoholOptions)
func Amount(amount int) OrderAlCoholOption {
    return func(opts *OrderAlCoholOptions) {
        opts.Amount = amount
    }
}
type Customer interface {
	OrderAlCohol(opts ...OrderAlCoholOption)
	OrderSoftdrink(amount int)
	OrderFood(amount int)
	GetTotalAmount() int
}
type Children struct {
    TotalAmount int
}
func (c *Children) OrderAlCohol(opts ...OrderAlCoholOption) {
    return
}
func (c *Children) OrderSoftdrink(amount int) {
    c.TotalAmount += amount
}
func (c *Children) OrderFood(amount int) {
    c.TotalAmount += amount
}
func (c *Children) GetTotalAmount() int {
    return c.TotalAmount
}
type Adult struct {
    Children
    HasOrderedAlcohol bool
}
func (a *Adult) OrderAlCohol(opts ...OrderAlCoholOption) {
    defaultOpts := &OrderAlCoholOptions {
        Amount: 500,
    }
    for _, opt := range opts {
        opt(defaultOpts)
    }
    a.TotalAmount += defaultOpts.Amount
    a.HasOrderedAlcohol = true
}
func (a *Adult) OrderSoftdrink(amount int) {
    a.TotalAmount += amount
}
func (a *Adult) OrderFood(amount int) {
    if a.HasOrderedAlcohol {
        a.TotalAmount += amount - 200
    } else {
        a.TotalAmount += amount
    }
}
func main(){
    var n, k int
    fmt.Scan(&n, &k)
    var c []Customer
    for i := 0; i < n; i++ {
        var age int
        fmt.Scan(&age)
        if age >= 20 {
            c = append(c, &Adult{
                Children: Children{TotalAmount: 0},
                HasOrderedAlcohol: false,
            })
        } else {
            c = append(c, &Children{TotalAmount: 0})
        }
    }
    // 退店した人の数
    cnt := 0
    for i := 0; i < k; i++ {
        var s, amount int
        var o string
        fmt.Scan(&s, &o)
        if o == "alcohol" {
            fmt.Scan(&amount)
            c[s - 1].OrderAlCohol(Amount(amount))
        } else if o == "softdrink" {
            fmt.Scan(&amount)
            c[s - 1].OrderSoftdrink(amount)
        } else if o == "food" {
            fmt.Scan(&amount)
            c[s - 1].OrderFood(amount)
        } else if o == "0" {
            c[s - 1].OrderAlCohol()
        } else if o == "A" {
            fmt.Println(c[s - 1].GetTotalAmount())
            cnt++
        }
    }
    fmt.Println(cnt)
}

Goで静的メンバのような挙動をしたい場合、パッケージ変数を使うのがよいようです。

一応その実装もしました。

package main
import "fmt"
// 退店人数管理のためのパッケージグローバル変数を定義
var leaveCount = 0
// OrderAlCohol関数に対するデフォルト値設定のためのOptions構造体を定義
type OrderAlCoholOptions struct {
    Amount int
}
type OrderAlCoholOption func(*OrderAlCoholOptions)
func Amount(amount int) OrderAlCoholOption {
    return func(opts *OrderAlCoholOptions) {
        opts.Amount = amount
    }
}
type Customer interface {
	OrderAlCohol(opts ...OrderAlCoholOption)
	OrderSoftdrink(amount int)
	OrderFood(amount int)
	GetTotalAmount() int
}
type Children struct {
    TotalAmount int
}
func (c *Children) OrderAlCohol(opts ...OrderAlCoholOption) {
    return
}
func (c *Children) OrderSoftdrink(amount int) {
    c.TotalAmount += amount
}
func (c *Children) OrderFood(amount int) {
    c.TotalAmount += amount
}
func (c *Children) GetTotalAmount() int {
    return c.TotalAmount
}
type Adult struct {
    Children
    HasOrderedAlcohol bool
}
func (a *Adult) OrderAlCohol(opts ...OrderAlCoholOption) {
    defaultOpts := &OrderAlCoholOptions {
        Amount: 500,
    }
    for _, opt := range opts {
        opt(defaultOpts)
    }
    a.TotalAmount += defaultOpts.Amount
    a.HasOrderedAlcohol = true
}
func (a *Adult) OrderSoftdrink(amount int) {
    a.TotalAmount += amount
}
func (a *Adult) OrderFood(amount int) {
    if a.HasOrderedAlcohol {
        a.TotalAmount += amount - 200
    } else {
        a.TotalAmount += amount
    }
}
func main(){
    var n, k int
    fmt.Scan(&n, &k)
    var c []Customer
    for i := 0; i < n; i++ {
        var age int
        fmt.Scan(&age)
        if age >= 20 {
            c = append(c, &Adult{
                Children: Children{TotalAmount: 0},
                HasOrderedAlcohol: false,
            })
        } else {
            c = append(c, &Children{TotalAmount: 0})
        }
    }
    for i := 0; i < k; i++ {
        var s, amount int
        var o string
        fmt.Scan(&s, &o)
        if o == "alcohol" {
            fmt.Scan(&amount)
            c[s - 1].OrderAlCohol(Amount(amount))
        } else if o == "softdrink" {
            fmt.Scan(&amount)
            c[s - 1].OrderSoftdrink(amount)
        } else if o == "food" {
            fmt.Scan(&amount)
            c[s - 1].OrderFood(amount)
        } else if o == "0" {
            c[s - 1].OrderAlCohol()
        } else if o == "A" {
            fmt.Println(c[s - 1].GetTotalAmount())
            leaveCount++
        }
    }
    fmt.Println(leaveCount)
}

ただ、グローバル変数は業務で使用する場合、Goroutineのような並列環境で動くことも想定して作るのが普通です。

(というより、その辺の問題に対応すると大変なので使わなくていいのであればグローバル変数は作らないのが一番いいと思います)

ということで今回はこれで👍