Go, первоклассные функции и лучшие практики - PullRequest
0 голосов
/ 28 апреля 2020

В течение последних нескольких дней я был на пути к лучшему, чтобы подойти к вопросу о первоклассных функциях (назначении вызываемой переменной для некоторой переменной) и лучших практик с точки зрения эффективности.

Допустим, я программирую карточную игру Yugioh, и я хочу, чтобы каждая отдельная карта типа карты имела как минимум следующие атрибуты:

type card struct {
    name string
    text string
}

Я боролся с идеей о том, где ( и как) программировать индивидуальную функциональность каждой карты. В настоящее время я убежден, что лучшее место для первоклассной функции - это type card struct, и создайте новый атрибут как «вызываемый», как я бы это сделал в Python (Go детская площадка ).

package main

import "fmt"


type card struct {
    name string
    text string
    f interface{}
}

type monsterCard struct {
    card
    attack int
    defense int
}

type buff func(target *monsterCard) // Could be defined in a second file

type swap func(target *monsterCard, value int) // ditto

var increaseAttack buff = func(target *monsterCard)  { // ditto
    target.attack += 100
}

var swichStats swap = func(target *monsterCard, value int) { // ditto
    attack := target.attack
    target.attack = value
    target.defense = attack
}

func main()  {
    m1 := monsterCard{
        card:    card{
            name: "Celtic Guardian",
            f:    increaseAttack,
        },
        attack:  1400,
        defense: 1200,
    }
    m2 := monsterCard{
        card:    card{
            name:     "Dark Magician",
            f:         swichStats,
        },
        attack:  2500,
        defense: 2100,
    }
    var monsters = [2]monsterCard{m1, m2}
    for _, m := range monsters {
        fmt.Println(m)
        switch m.f.(type) {
        case buff:
            m.f.(buff)(&m)
        case swap:
            m.f.(swap)(&m, m.defense)
        default:
            fmt.Printf("%T", m.f)
        }
        fmt.Println(m)
    }
}

Я не очень хорош в отношении эффективного кода, и я полностью понимаю, что я мог бы оптимизировать здесь рано; однако мне нужно будет запрограммировать сотни таких карт, и если наличие этих вызываемых элементов существует в глобальном масштабе с сильной зависимостью от утверждения типа, что замедлит работу программы, то у меня возникнут проблемы с реорганизацией кода.

Есть ли какие-то явные проблемы, которые вы можете увидеть с моей методологией? Правильно ли я работаю с первоклассными функциями или есть какие-то явные проблемы с производительностью, которые я не вижу? Любая помощь будет принята с благодарностью!

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

При необходимости вы можете использовать простые функции и замыкания:

type card struct {
    name string
    text string
    fn   func(*monsterCard)
}

type monsterCard struct {
    card
    attack  int
    defense int
}

func (mc *monsterCard) call() {
    mc.fn(mc)
}

func increaseAttack(mc *monsterCard) {
    mc.attack += 100
}

func switchStats(mc *monsterCard) {
    mc.attack, mc.defense = mc.defense, mc.attack
}


func updateTextAndAttack(text string, attack int) func(mc *monsterCard) {
    return func(mc *monsterCard) {
        mc.text, mc.attack = text, attack
    }
}

https://play.golang.com/p/v_RbObnu7sN

Вы также можете использовать простые методы и замыкания при необходимости:

type card struct {
    name string
    text string
}

type monsterCard struct {
    card
    attack  int
    defense int
}

func (mc *monsterCard) increaseAttack() {
    mc.attack += 100
}

func (mc *monsterCard) switchStats() {
    mc.attack, mc.defense = mc.defense, mc.attack
}

func (mc *monsterCard) updateTextAndAttack(text string, attack int) func() {
    return func() {
        mc.text, mc.attack = text, attack
    }
}

https://play.golang.com/p/Eo1mm-seldA

0 голосов
/ 28 апреля 2020

Спасибо всем, кто помог мне с этим ответом. Похоже, что я все еще использую свой настрой языка сценариев, чтобы попытаться решить проблемы на скомпилированном языке. Вместо того чтобы пытаться создавать интерфейсы, которые в конечном итоге приводят к затруднению чтения кода, мне нужно быть более строгим в своих определениях пользовательских типов и реализовывать разные типы функций для каждого типа эффекта карты. Такое строгое соблюдение также позволит использовать в игре карты с несколькими эффектами.

package main

type card struct {
    name string
    text string
}

type monsterCard struct {
    card
    attack int
    defense int
}

type buffEffect struct {
    monsterCard
    fn buff
}

type setValueEffect struct {
    monsterCard
    fn swap
}

type buff func(target *monsterCard)

type swap func(target *monsterCard, value int)

var increaseAttack buff = func(target *monsterCard)  {
    target.attack += 100
}

var setAttackValue swap = func(target *monsterCard, value int) {
    target.attack = value
}

func main()  {
    m1 := buffEffect{
        monsterCard: monsterCard{
            card:    card{
                name: "Celtic Guardian",
            },
            attack:  1400,
            defense: 1200,
        },
        fn:          increaseAttack,
    }
    m2 := setValueEffect{
        monsterCard: monsterCard{
            card:    card{
                name: "Dark Magician",
            },
            attack:  2500,
            defense: 2100,
        },
        fn:          setAttackValue,
    }
    m1.fn(&m1.monsterCard)
    m2.fn(&m2.monsterCard, 100)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...