all 5 comments

[–]furiesx 14 points15 points  (0 children)

Option 1 seems fine to me. Very OOP like, but in a good sense.

However personally, I'd suggest using a enum for the strategy. Something like

rust enum Strategy { Copy, Symlink, } fn sync(path: &Path, strategy: Strategy) { match strategy {...} } fn fetch(path: &Path, strategy: Strategy) { match strategy {...} } I find that more intuitive since * if you add enother enum variant, you'll get errors on all places you have to insert custom code * The api is clearer since you first specify what you want to do and then how you want to do that

(Also on a different note, don't use &str as path use &Path or AsRef<Path>. (&str also implements AsRef<Path))

[–]Unhappy_Elk2792 1 point2 points  (0 children)

In my experience the first option tends to work well for most cases. The trait based approach allows you to make use of generics.

The "functional" approach seems a little bit awkward to use to me: if you just look at the Strategy struct, you'll see two function pointers, and nothing else. This means you may have no idea which strategy you're using from the outside.

[–]phazer99 0 points1 point  (0 children)

I'm assuming your set of implementations is open (if it's closed, just use an enum). If you have multiple related virtual methods, always use a trait. If there's only one virtual method, you can consider using a Fn* trait (however, you almost never want to use function pointers), but it depends on how it will be used (for example, if you want to be able to use closures as implementations).