-1

Summary: Local Method call (inside same file) results in: [govet] undeclared name: QueryPart [Error]

Edit: Please see summary of mistakes and correction at bottom of post.

I'm very new to Go, and am trying to build some simple Hyperledger Fabric chaincode.

In the following code, I have a method QueryPart which I can call successfully. I wanted to see if I could write another method QueryPartSpecial to call the original QueryPart method (and then do some other stuff), but I'm getting a fatal error: [govet] undeclared name: QueryPart [Error]

  231 //QueryPart: queries a single part from the ledger (with provided partID)
  232 func (s *SmartContract) QueryPart(ctx contractapi.TransactionContextInterface, partID string) (*Part, error) {
  233   assetJSON, err := ctx.GetStub().GetState(partID)
  234   if err != nil {
  235     return nil, fmt.Errorf("failed to read from world state: %v", err)
  236   }
  237   if assetJSON == nil {
  238     return nil, fmt.Errorf("the asset %s does not exist", partID)
  239   }
  240   
  241   var part Part
  242   err = json.Unmarshal(assetJSON, &part)
  243   if err != nil {
  244     return nil, err
  245   }
  246 
  247   return &part, nil
  248 }
  249 
  250 //QueryPartSpecial: calls QueryPart and does some other experimental stuff on it
  251 func QueryPartSpecial(partID string) (*Part, error) {
✘ 252   part, err := QueryPart(partID)
  253   //placeholder for some other code
  254   return part, err
  255 } 

Why would I get this error since func QueryPart is clearly declared above?

Note: This question appears very similar to the following questions:
Function in same package undefined
Go: undefined function in same package

However, the main difference from these other questions is that my two functions reside inside in the same [file].go.

Note 2: the error I am getting is a linting error, but is also preventing me from compiling/installing the chaincode.

Edit: What I did wrong and what I learned:

The error I received was due to problems with the QueryPartSpecial method, rather than the QueryPart method.

As a new learner to Go, I made several mistakes:

  1. Confusing methods and functions. (In my original post, I referred to both methods as functions.)
  2. Incorrectly constructing QueryPartSpecial: As Lucas pointed out, I did not include any object in QueryPartSpecial. By modifying this function to a method with a pointer receiver of SmartContract, I could provide an object when calling QueryPart.
  3. Incorrectly calling the method QueryPart: Since methods operate on a object, they should be called on an object.

This is my corrected code (which is functional without an error returned):

255 //QueryPartSpecial: calls QueryPart and does some other experimental stuff on it
256 func (s *SmartContract) QueryPartSpecial(ctx contractapi.TransactionContextInterface, partID string) (*Part, error) {
257   part, err := s.QueryPart(ctx,partID)
258   //placeholder for some other code
259   return part, err
260 } 

(Thank you, Lucas, Adrian, and Volker for your help and for steering me in the right direction.)

jabberwocky
  • 115
  • 1
  • 11
  • 1
    Please learn Go, e.g. via tour.golang.org. QueryPart is a method and thus cannot be called without an opbject. – Volker Dec 14 '20 at 15:54
  • `QueryPart` is a method of `*SmartContract`, so it must be called on a `*SmartContract` instance. `QueryPartSpecial` is a plain function with no receiver. – Adrian Dec 14 '20 at 15:55
  • @Volker What do you mean by an "object" in Golang? – jabberwocky Dec 14 '20 at 20:27
  • Thank you Adrian and Volker for your feedback. (I've been through the tour.golang already, but admittedly am still trying to learn.) I understanding that QueryPart is a method (and not a function like I first stated). However, I'm still confused as to why I get the mentioned error. (Note that the error is not present if I remove lines 250-255.) – jabberwocky Dec 14 '20 at 20:38
  • Object: An instance of a type. Learn the language. – Volker Dec 14 '20 at 21:20

1 Answers1

1

You are using a pointer receiver for the method QueryPart. From the docs:

Methods with pointer receivers can modify the value to which the receiver points

So you will need to call the method on the object itself, something similar to this:

contract := SmartContract{}
contract.QueryPart(ctx)

Or to call it directly remove the receiver (convert to a function as commented above by Adrian):

func QueryPart(...) // (s *SmartContract) receiver removed
Lucas
  • 9,871
  • 5
  • 42
  • 52