Because I don't want the code I'm running to change out from under me when I tell it to run because some dependency got updated (or for any other reason, for that matter). That's a recipe for disaster.
Running the code is a separate step from determining what code I am going to run; the latter includes determining exactly what versions of all dependencies I am going to run. The two should not be combined.
If the versions are locked, then after the first download, nothing should be downloaded again unless I explicitly change a requirement and/or a version. So after the first time with a given set of requirements and versions, I suppose "go run" would be fine since it won't actually download anything.
But for that first time, I still want to separate the two steps, for the reasons I've given elsewhere in this discussion.
Dependencies won’t update themselves since they are locked to their versions. If the developer manually triggers an update, and the dependencies aren’t compatible, either the code wouldn’t compile or it’s behave weird. In both cases, what’s the advantage of separating out the fetch-dependencies part?
That's why you have a go.mod file that specifies the dependencies for you. Just run go mod tidy and it generates/updates it for you. You get these reproducible builds for free this way.
Running the code is a separate step from determining what code I am going to run; the latter includes determining exactly what versions of all dependencies I am going to run. The two should not be combined.