dongshi2141 2019-03-20 17:35
浏览 87
已采纳

地图似乎在递归中删除值

I've been working on a problem and I figured I would demonstrate it using a pokemon setup. I am reading from a file, parsing the file and creating objects/structs from them. This normally isn't a problem except now I need to implement interface like inheriting of traits. I don't want there to be duplicate skills in there so I figured I could use a map to replicate a set data structure. However it seems that in the transitive phase of my recursive parsePokemonFile function (see the implementsComponent case), I appear to be losing values in my map.

I am using the inputs like such:

4 files

Ratatta:

name=Ratatta
skills=Tackle:normal,Scratch:normal

Bulbosaur:

name=Bulbosaur
implements=Ratatta
skills=VineWhip:leaf

Oddish:

name=Oddish
implements=Ratatatt
skills=Acid:poison

Venosaur:

name=Venosaur
implements=bulbosaur,oddish

I'm expecting the output for the following code to be something like

Begin!
{Venosaur [{VineWhip leaf} {Acid poison} {Tackle normal} {Scratch normal}]}

but instead I get

Begin!
{Venosaur [{VineWhip leaf} {Acid poison}]}

What am I doing wrong? Could it be a logic error? Or am I making an assumption about the map holding values that I shouldn't?

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

// In order to create a set of pokemon abilities and for ease of creation and lack of space being taken up
// We create an interfacer capability that imports the skills and attacks from pokemon of their previous evolution
// This reduces the amount of typing of skills we have to do.
// Algorithm is simple. Look for the name "implements=x" and then add x into set.
// Unfortunately it appears that the set is dropping values on transitive implements interfaces

func main() {
     fmt.Println("Begin!")
    dex, err := parsePokemonFile("Venosaur")
    if err != nil {
        fmt.Printf("Got error: %v
", err)
    }
    fmt.Printf("%v
", dex)
}

type pokemon struct {
    Name   string
    Skills []skill
}

type skill struct {
    SkillName string
    Type      string
}

func parsePokemonFile(filename string) (pokemon, error) {
    file, err := os.Open(filename)
    if err != nil {
        return pokemon{}, err
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    var builtPokemon pokemon
    for scanner.Scan() {
        component, returned := parseLine(scanner.Text())
        switch component {
        case nameComponent:
            builtPokemon.Name = returned
        case skillsComponent:
            skillsStrings := strings.Split(returned, ",")
            var skillsArr []skill
            // split skills and add them into pokemon skillset
            for _, skillStr := range skillsStrings {
                skillPair := strings.Split(skillStr, ":")
                skillsArr = append(skillsArr, skill{SkillName: skillPair[0], Type: skillPair[1]})
            }
            builtPokemon.Skills = append(builtPokemon.Skills, skillsArr...)
        case implementsComponent:
            implementsArr := strings.Split(returned, ",")
            // create set to remove duplicates
            skillsSet := make(map[*skill]bool)
            for _, val := range implementsArr {
                // recursively call the pokemon files and get full pokemon
                implementedPokemon, err := parsePokemonFile(val)
                if err != nil {
                    return pokemon{}, err
                }
                // sieve out the skills into a set
                for _, skill := range implementedPokemon.Skills {
                    skillsSet[&skill] = true
                }
            }
            // append final set into the currently being built pokemon
            for x := range skillsSet {
                builtPokemon.Skills = append(builtPokemon.Skills, *x)
            }
        }
    }
    return builtPokemon, nil
}

type component int

// components to denote where to put our strings when it comes time to assemble what we've parsed
const (
    nameComponent component = iota
    implementsComponent
    skillsComponent
)

func parseLine(line string) (component, string) {
    arr := strings.Split(line, "=")
    switch arr[0] {
    case "name":
        return nameComponent, arr[1]
    case "implements":
        return implementsComponent, arr[1]
    case "skills":
        return skillsComponent, arr[1]
    default:
        panic("Invalid field found")
    }
}
  • 写回答

1条回答 默认 最新

  • dongxi1965 2019-03-20 18:31
    关注

    This has nothing to do with Golang maps dropping any values.

    The problem is that you are using a map of skill pointers and not skills. Two pointers to the same skill content can be different.

    skillsSet := make(map[*skill]bool)

    If you change this to map[skill]bool, this should work. You may try it out!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用三极管设计—个共射极放大电路
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示