Access a variable defined in a callback/closure and using filepath.Walk

331 views
Skip to first unread message

jgra...@gmail.com

unread,
Sep 9, 2014, 8:57:24 AM9/9/14
to golan...@googlegroups.com
Hi,

the object of this message might no be clear and misleading, sorry about it.

I'm new to golang, and I don't know how to access a variable outside a closure.
Here's my example.

I have a package using filepath.Walk.
    func Walk(root string, walkFn WalkFunc) error

//walker/walker.go
package walker

import (
       
"fmt"
       
"os"
)

var counterDirs int
var counterFiles int

func
WalkPath(path string, f os.FileInfo, err error) error {

       
if err != nil {
                fmt
.Println("Error ", error)
       
} else {
                sum
+= f.Size()

               
if f.IsDir() {
                        counterDirs
++
               
} else {
                        counterFiles
++
               
}
       
}
       
return nil
}



//---
//main.go
package main

import "filepath"

func main
() {
        err
= filepath.Walk(filepath, walker.WalkPath)

       
// access counterDirs and counterFiles and do something with them
}

Very close to http://stackoverflow.com/questions/11336048/how-am-i-meant-to-use-filepath-walk-in-go. In this SOF example, I would like to access numScanned outside ScanAllFiles function.

AFAIK I cannot use a higher order function as the signature
 type WalkFunc func(path string, info os.FileInfo, err error) error

is required, so cannot return counterDirs and counterFiles values for treatment. I don't to put the treatment in WalkPath. I cannot use a "global" variable as it will be common for all calls to walker.WalkPath. Defining a Higher Order Function doesn't help, or cannot see how.
Sorry if it's a beginner question, but what's the best way to deal with this kind of issue. Should surely think in another way...
Thanks in advance,
jgr






chris dollin

unread,
Sep 9, 2014, 9:21:44 AM9/9/14
to jgra...@gmail.com, golang-nuts
Have WalkPath take as an extra parameter a pointer-to-struct
where the struct has countDirs and countFiles fields that it
(by which I mean, WalkPath) updates as needed,
and pass to filePath.Walk

func (path string, info os.FileInfo, err error) error {
return walker.WalkPath(&mystruct, info, err)
}

having declared

var myStruct theStructTypeWithTheCountersInIt

Chris
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--
Chris "allusive" Dollin

jgra...@gmail.com

unread,
Sep 10, 2014, 3:50:47 AM9/10/14
to golan...@googlegroups.com, jgra...@gmail.com
Hi,

thank you for your answer ehedgehog, but... I'm sorry, I can't get it. I don't know how to deal with MyStruct. How to pass it as param et get it from main.go ? I don't understand your function
func (path string, info os.FileInfo, err error) error {
       
return walker.WalkPath(&mystruct, info, err)
   
}

where/how should I use it as filepath.Walk
expects the right signature...

package walker

import (
   
"fmt"
   
"os"
)

var counterDirs int
var counterFiles int
var sum int64

type
MyStruct struct {
   
CounterDirs  int
   
CounterFiles int
   
Sum          int64
}

func
WalkPath(path string, f os.FileInfo, err error) error {


    myValue
:= &MyStruct{} // I know it shouldn't be here!!
   
if err != nil {
        fmt
.Println(err)
   
} else {
        sum
+= f.Size()
        myValue
.Sum = sum

       
if f.IsDir() {
            counterDirs
++
            myValue
.CounterDirs = counterDirs
       
} else {
            counterFiles
++
            myValue
.CounterFiles = counterFiles
       
}
   
}
    fmt
.Printf("total 1: %d dirs : %d, files : %d\n", sum, counterDirs, counterFiles)
   
//myValue := &MyStruct{CounterDirs: counterDirs, CounterFiles: counterFiles, Sum: sum}
    fmt
.Printf("total 2: %d dirs : %d, files : %d\n", myValue.Sum, myValue.CounterDirs, myValue.CounterFiles)
   
return nil
}

//main.go
package main

import (
   
"fmt"
   
"log"
   
"path/filepath"

   
"walker"
)


func main
() {
    path
:= "path/to/folder"
    err
:= filepath.Walk(path, walker.WalkPath)

   
if err != nil {
        log
.Println(err.Error())
   
}

    myValue
:= &MyType{CounterDirs: 5, CounterFiles: 10, Sum: 180}
    fmt
.Println("myValue = ", myValue)

    fmt
.Println("2nd -----------------")
   
// counters continue to grow... They should be reset...
    err
= filepath.Walk(path, walker.WalkPath)

   
if err != nil {
        log
.Println(err.Error())

   
}

   
// access counterDirs and counterFiles and do something with them

    doSomethingWith
(counterDirs, counterFiles, Sum)
}


Hard time with closures and pointers not fully understood...
Thanks a lot,
jgr

Jérôme Champion

unread,
Sep 10, 2014, 5:17:26 AM9/10/14
to golan...@googlegroups.com, jgra...@gmail.com
You would have better answer if you posted a small example in http://play.golang.org/ .

I would do like this : http://play.golang.org/p/L-MnkEv8Qx

chris dollin

unread,
Sep 10, 2014, 5:18:48 AM9/10/14
to jgra...@gmail.com, golang-nuts
On 10 September 2014 08:50, <jgra...@gmail.com> wrote:
> Hi,
>
> thank you for your answer ehedgehog, but... I'm sorry, I can't get it. I
> don't know how to deal with MyStruct. How to pass it as param et get it from
> main.go ? I don't understand your function
> func (path string, info os.FileInfo, err error) error {
> return walker.WalkPath(&mystruct, info, err)
> }
>
> where/how should I use it as filepath.Walk
> expects the right signature...

func (path string, info os.FileInfo, err error) error {
return walker.WalkPath(&mystruct, info, err)
}

has the right signature. You can pass it to filepath.Walk in
main.main, which is where you'd declare mystruct.

When filepath.Walk calls the func, that will in turn call
WalkPath passing in the address of the structure.


>
> package walker
>
> import (
> "fmt"
> "os"
> )
>
> var counterDirs int
> var counterFiles int
> var sum int64
>
> type MyStruct struct {
> CounterDirs int
> CounterFiles int
> Sum int64
> }
>
> func WalkPath(path string, f os.FileInfo, err error) error {
>

func WalkPath(myValue *MyStruct, path string, f os.FileInfo, err error) error {

> myValue := &MyStruct{} // I know it shouldn't be here!!

remove
err := filepath.Walk(path, func (path string, info os.FileInfo, err
error) error {
return walker.WalkPath(&mystruct, info, err)
})

>
> if err != nil {
> log.Println(err.Error())
> }
>
> // access counterDirs and counterFiles and do something with them
> doSomethingWith(counterDirs, counterFiles, Sum)
> }
>
> Hard time with closures and pointers not fully understood...

Can you be more specific about the bits you don't
understand? Closures are just functions that access
variables declared outside the function, usually local
variables of an enclosing function; when the closure
runs it can tinker with those outside variables.

Chris

--
Chris "allusive" Dollin

rjeczalik

unread,
Sep 10, 2014, 5:25:43 AM9/10/14
to jgra...@gmail.com, golang-nuts
On 10 September 2014 09:50, <jgra...@gmail.com> wrote:
> Hard time with closures and pointers not fully understood...

This is more about proper abstraction, rather than implementation problem. You could use middle-ware technique widely used for the http.HandlerFunc, like:

jgra...@gmail.com

unread,
Sep 11, 2014, 4:57:05 AM9/11/14
to golan...@googlegroups.com, jgra...@gmail.com
Thank you very much everyone, I've realized something I've learnt about go kind of object orientation. Thanks for playground I should also have thought about.
Reply all
Reply to author
Forward
0 new messages