是谷歌的"走出去"语言多值返回声明的替代例外?
-
13-09-2019 - |
题
它似乎对我是谷歌的替代办法的例外情况是
- 去:多值回报的"返回val,err;"
- 去、C++:nil检查(早日返回)
- 去、C++:"处理那该死的错误"(我的语)
C++:assert(表)
去:推迟/恐慌/恢复有语言功能后加入这个问题
是多值返回有用的,足以充当一个选择吗?为什么是"声称"考虑替代方案?Google想它好吧如果程序的中止,如果发生错误的,是不正确处理的?
一个去的不寻常特征是,其功能和方法可能返回多的价值。这可以用来提高几个笨拙的习惯用语中的C节目:在带错误返回(例如-1EOF)和修改的参数。
在C、写错误的信号通过 负计数的错误代码 分泌的在挥发性的位置。在去,写信可以返回计数和一个 错误:"是的,你写了一些字但是 不是所有的人都是因为你填补了 设备"。签名的文件。写 在包os是:
func (file *File) Write(b []byte) (n int, err Error)
和因为该文件说, 返回的号码写的字节 并非为零的错误,当n!= len(b)。这是一种常见的模式;看看 部分上的错误处理更多 例子。
返回或结果"参数"的 去功能可以给出名字和 作为经常变量,就像 进入的参数。当命名, 他们都是初始化为零 值用于它们的类型时 功能开始;如果功能 执行返回的声明没有 参数,目前的价值 结果参数被用作 返回的价值观。
名字不是强制性的,但他们 可以编码的更短的和更清晰:他们的文件。如果我们的名字 结果nextInt它变得显而易见的 其返回int。
func nextInt(b []byte, pos int) (value, nextPos int) {
因为命名的结果是初始化和绑到一个 朴实的回报,他们可以简化为 为澄清。这里有一个版本的 io.ReadFull使用它们:
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
for len(buf) > 0 && err == nil {
var nr int;
nr, err = r.Read(buf);
n += nr;
buf = buf[nr:len(buf)];
}
return;
}
例外情况是类似的故事。一些设计为例外已经提出但每个会大幅增加复杂性的语言和运行时间。由于其本身的性质,例外的跨职能和或许甚至go程序;他们有广泛的影响。还有人担心的作用,他们将对图书馆。它们是,通过定义、特殊但经验与其他语言,支持它们显示它们具有深刻的影响,库和接口的规范。这会是很好找到一个的设计,允许他们是真正的例外,而不鼓励共同的错误转到特殊的控制流动,需要每一个程序员进行补偿。
如仿制药,例外情况保持一个开放的问题。
决定:
在他们的脸上,使用的好处 例外情况超过成本, 特别是在新的项目。但是, 对现有码,介绍 例外情况具有影响的所有 依赖码。如果可以例外 传播超出了一个新的项目, 还成为有问题的整合 新项目为现有的 异常的代码。因为大多数 现有的C++码在谷歌是不是 准备处理例外情况, 是比较难以通过 新代码生成的例外情况。
鉴于谷歌的现代码是 不异常宽容的费用 使用例外的是有点大 比费用在一个新的项目。转换过程将会是缓慢 而且容易出错。我们不相信 的 可用的替代品 例外情况,例如错误代码 断言, 引入的一个显着的 负担。
我们的建议反对使用例外情况是 不取决于或哲学 道德理由,但实际的。因为我们想使用我们的 开放源码项目在谷歌和 这是很难做到的,因此,如果那些 项目使用的例外情况,我们需要 建议对例外情况在谷歌 开放源码项目。事情 可能会是不同的,如果我们有 要做到这一切再次从头开始。
推迟的发言使我们认为关闭每个文件的权利打开后它保证,无论数量的回声明的功能,本文件将被关闭。
该行为的推迟发言是简单的和可预测的。有三个简单的规则:
1.一个推迟的功能的论点进行评估时推迟的发言进行评估。
在这个例子,表达"我"是评估的时呼吁释放被推迟。延期的话,将打印"0"功能后返回。
func a() { i := 0 defer fmt.Println(i) i++ return }
2.推迟功能的电话是执行在最后一次在第一个出来以后,周围的功能返回。 这一功能打印"3210":
func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } }
3.推迟的功能可以阅读并分配给返回的功能,名为返回的价值观。
在这个例子中,一个延迟的功能,增加返回值后我周围的功能返回。因此,这一功能将返回2:
func c() (i int) { defer func() { i++ }() return 1 }
这便于修改的错误返回价值的功能;我们将看到这样的一个例子。
恐慌是一个建立在功能停止普通流动的控制和开始恐慌。 当功能F呼叫恐慌,执行F停止,任何推迟职能F执行正常,然后F返回其来电。呼叫者、F则的行为就像一个叫恐慌。该过程继续起叠,直到所有功能在目前的执行程序已经返回,在这一点的程序的崩溃。恐慌可以发起援引恐慌。他们也可以是由运行时间错误,例如超出范围的阵列的访问。
恢复是一个建立在功能,恢复控制的一个惊慌失措的执行程序. 恢复仅仅是有用的内推迟职能。在正常执行,呼吁恢复将返回的零和没有其他效果。如果目前的执行程序是恐慌,电话来 恢复将捕获的价值给予恐慌和恢复正常执行.
这里有一个例子程序证明了该机制的恐慌和推迟:
<snip>
对于一个真实世界的例子的恐慌和恢复,见id包的离去标准图书馆。它解书的编码数据的一个组递归功能。当格式错误JSON遇到的分析器呼叫恐慌是放松堆顶级别功能的电话,恢复从恐慌和返回的一个适当的误差值(参见'错误"和"解组的职能在解码。go)。有一个类似的例子,这种技术在编译程序的regexp包。《公约》在去图书馆是,即使一揽子使用恐慌的境内,其外部API仍然提出了明确的错误返回值。
其它使用的推迟(超出了该文件。Close()给出的例子前)包括释放一个互斥:
mu.Lock() defer mu.Unlock
解决方案
多回报不是唯一要去的,他们不能代替用于例外情况。在C(或C++)的条款,他们是一个简明扼要和用户友好的替代回返的结构(物体)包含的多种价值观。
他们这样做提供了方便的手段,指明错误的,如果这就是你的意思。
为什么是"声称"考虑替代方案?
声称最初是进行调试。他们停止程序的情况下,它是在"不可能"的国家,一个设计说的不应该发生,但已无论如何。返回一个错误是不可能有多大帮助。代码基显然不起作用,所以如何在地球上,它可以成功地恢复吗?为什么你甚至希望它,当有一个错误,需要注意的?
使用声称,在生产码是一个不同的问题-显然存在性能和代码尺寸的问题,所以通常的做法是清除他们一旦你的代码分析和测试相信你说的"不可能"的情况真的是不可能的。但是,如果你正在运行的代码,在这个级别的偏执,它的审计本身,然后你大概也猜疑如果你让它进行的运行中"不可能"的状态,那么它可能会做一些危险地破碎:破坏宝贵的数据,超越一堆分配以及或许是创造安全漏洞。所以,你只是想关闭,尽快。
你的东西使用称为真的不是相同的东西,你使用的例外情况为:当编程语言,如C++、Java提供的例外情况"不可能"的情况(logic_error
, ArrayOutOfBoundsException
),他们无意中鼓励了一些程序员认为他们的程序 应该 试图从中恢复的情况下实际上他们出的控制。有时候,这是适当的,但是Java建议不要抓RuntimeExceptions是有一个很好的理由。很偶然这是一个好主意抓住一个,这就是为什么它们的存在。几乎总是这不是一个好主意追赶他们,这意味着它们量,以制止程序(或至少在线)。
其他提示
你应该读一两个条款的例外情况,以实现返回值不例外。不在C'带'的方式或在任何其他方式。
如果没有进入一个深入参数,例外的是要引发错误的条件是发现并抓获其中的错误的条件可以进行有意义的处理。回值仅仅是处理在第一次功能层次叠,这可能或不可能不如何处理该问题。一个简单的例子将是一个配置文件,该文件可以检索的数值如串,并且还支持处理进入类型回声明:
class config {
// throws key_not_found
string get( string const & key );
template <typename T> T get_as( string const & key ) {
return boost::lexical_cast<T>( get(key) );
}
};
现在的问题是如何处理的,如果关键没有被发现。如果您使用的返回代码(说的去向)问题, get_as
必须处理的错误代码 get
并采取相应的行动。因为它真的不知道该怎么做,唯一明智的事情是 手动 传播错误的上游:
class config2 {
pair<string,bool> get( string const & key );
template <typename T> pair<T,bool> get_as( string const & key ) {
pair<string,bool> res = get(key);
if ( !res.second ) {
try {
T tmp = boost::lexical_cast<T>(res.first);
} catch ( boost::bad_lexical_cast const & ) {
return make_pair( T(), false ); // not convertible
}
return make_pair( boost::lexical_cast<T>(res.first), true );
} else {
return make_pair( T(), false ); // error condition
}
}
}
实施者的类必须增加额外的代码以前的错误,代码变得混合在一起的实际逻辑的问题。C++这可能是更多负担沉重于在一种语言设计的多项任务(a,b=4,5
)但是,如果逻辑取决于可能的错误(在这里呼叫 lexical_cast
应该仅仅是执行,如果我们有一个实际的string)然后,你会需要的高速缓存值转变量。
它不走了,但在Lua、多返回是一种极为常见的成语,用于处理例外情况。
如果你有一个功能喜欢
function divide(top,bottom)
if bottom == 0 then
error("cannot divide by zero")
else
return top/bottom
end
end
然后当 bottom
为0,一个例外将是提出和程序的执行将停止,除非你包裹的功能 divide
在一个 pcall
(或受保护的呼叫).
pcall
总是返回的两个价值:第一个是结果是一个布尔告诉功能是否返回的成功,而第二个结果是返回值或错误信息。
以下(预谋)Lua段表示这种在用途:
local top, bottom = get_numbers_from_user()
local status, retval = pcall(divide, top, bottom)
if not status then
show_message(retval)
else
show_message(top .. " divided by " .. bottom .. " is " .. retval)
end
当然,你没有用 pcall
, ,如果功能你打电话已经返回的形式 status, value_or_error
.
多返回已经足够好对Lua几年来,以便同时,不 确保 那它够好转,就支持这一想法。
是的,错误的返回值是好的但不要捕捉真正意义上的例外处理...这是能力和管理的特殊情况下在其中一个通常不打算。
Java(即)的设计考虑的例外,海事组织是有效的工作流程 方案 他们有一点关于复杂的接口和图书馆的具有声明和版这些扔例外,但可惜的是例外的服务的一个重要作用栈多米诺骨牌。
认为替代的情况下,特殊的返回代码是有条件地处理在几十个方法的呼吁深。什么叠的痕迹看起来像在那里的犯罪行号码是什么?
这个问题是一个棘手的回答客观和观点上的例外可能有所不同。
但是,如果我们推测,我认为主要原因的例外情况不包括在去是因为它复杂的编译器,并可能导致不平凡的影响问题的时候编写库。例外情况是难以得到正确的,并且他们优先得到什么工作。
之间的主要差别处理差错通过返回的价值观和例外情况是,部队的例外情况的程序来处理不寻常的条件。你可以永远不会有一种"沉默的错误"除非明确地抓住一种例外做什么的追赶块。另一方面,你隐含的返回点到处内部的功能,这可以导致其他类型的错误。这是特别普遍使用C++管理存储器的明确和需要确保你不会失去指向你拥有的东西进行分配。
例的危险局势C++:
struct Foo {
// If B's constructor throws, you leak the A object.
Foo() : a(new A()), b(new B()) {}
~Foo() { delete a; delete b; }
A *a;
B *b;
};
多返回值使得更易于实现返回基于价值的错误处理,而不必依赖出的论据的功能,但是它不改变任何东西根本。
一些语言已经两个多返回的价值观和例外(或类似的机制)。一个例子是 Lua.
这是一个如何多返回值可能会工作c++。我不会写这些代码我自己,但我不认为这是完全出的问题使用这种办法。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// return value type
template <typename T>
struct RV {
int mStatus;
T mValue;
RV( int status, const T & rv )
: mStatus( status ), mValue( rv ) {}
int Status() const { return mStatus; }
const T & Value() const {return mValue; }
};
// example of possible use
RV <string> ReadFirstLine( const string & fname ) {
ifstream ifs( fname.c_str() );
string line;
if ( ! ifs ) {
return RV <string>( -1, "" );
}
else if ( getline( ifs, line ) ) {
return RV <string>( 0, line );
}
else {
return RV <string>( -2, "" );
}
}
// in use
int main() {
RV <string> r = ReadFirstLine( "stuff.txt" );
if ( r.Status() == 0 ) {
cout << "Read: " << r.Value() << endl;
}
else {
cout << "Error: " << r.Status() << endl;
}
}
如果你需要C++的方式做一个"可空的"目的使用的增强:可选< T>。你的测试它作为一个布尔,如果它计算结果真的那么你对它的有效T.