Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

rust - Why would I use divergent functions?

Reading through the Rust book, I came across an interesting topic — divergent functions:

Rust has some special syntax for ‘diverging functions’, which are functions that do not return:

fn diverges() -> ! {
    panic!("This function never returns!");
}

A diverging function can be used as any type:

let x: i32 = diverges();
let x: String = diverges();

What would be the use cases of a divergent function? The book says that

panic!() causes the current thread of execution to crash with the given message. Because this function will cause a crash, it will never return, and so it has the type !

That makes sense, but I can't think of where else a divergent function would be of use and it seems very localized to just panic!. I know there must be some useful scenarios out there for why they introduced divergent functions. Where would I likely see divergent functions in Rust?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It has several uses. It can be used for functions which are designed to panic or exit the program. panic!() itself is one such function, but it can also be applied to functions which wrap panic!(), such as printing out more detailed error information and then panicking.

It can also be used for functions that never return. If a function goes into an infinite loop, such as the main loop of a server, and thus never returns, it could be defined this way.

Another possible use would be a wrapper around the Unix exec family of functions, in which the current process is replaced with the one being executed.

It is useful to have such a type because it is compatible with all other types. In order to be type safe, Rust has to ensure that all branches of a match or if statement return the same type. But if there are some branches that are unreachable or indicate an error, you need some way to throw an error that will unify with the type returned by the other branches. Because ! unifies with all types, it can be used in any such case.

There is an interesting RFC (and discussion) at the moment that argues (in part) for expanding the places where ! can be used, arguing that it should be treated as a full fledged type like () is; ! being a type with no values that unifies with all other types, while () being a distinct type with a single value. I'm not sure I agree with the full RFC, but the discussion of treating ! as a full-fledged type is interesting and I think could be proposed separately from the rest of the RFC.

Update: Since I wrote the above, the part of the RFC about promoting ! to a full fledged type was split into a separate RFC and merged, and is in the process of being implemented (currently available in nightly builds behind a feature gate). As a full-fledged type, it can be used in more contexts, such as in Result<T, !> indicating a result that can never fail, or Result<!, E> as one that can never succeed. These are useful in generic contexts; if you have some trait that requires a method to return a result, but for that particular implementation it can only possibly succeed, you don't need to fill in some dummy error type.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...