天道酬勤,学无止境

什么时候使用包含守卫?(When to use include guards?)

问题

我知道在头文件中使用包含保护是为了防止某些东西被定义两次。 不过,使用此代码示例完全没问题:

foo.c

#include <stdio.h>
#include <string.h>
#include "bar.h"

int main() {
    printf("%d", strlen("Test String"));
    somefunc("Some test string...");
    return 0;
}

酒吧.h

#ifndef BAR_H_INCLUDED
#define BAR_H_INCLUDED
void somefunc(char str[]);
#endif

酒吧

#include <stdio.h>
#include <string.h>
#include "bar.h"

void somefunc(char str[]) {
    printf("Some string length function: %d", strlen(str));
}

上面的代码片段是用gcc -Wall foo.c bar.c -o foo编译的,没有错误。 但是, <stdio.h><string.h>都包含在没有包含保护的情况下。 当我将 bar.h 剥离到单个语句void somefunc(char str[]);时,仍然没有错误void somefunc(char str[]); . 为什么没有错误?

回答1

首先,包含守卫的主要目的是防止某些东西在同一个翻译单元中被声明两次。 “在同一翻译单元中”部分是这里的关键。 您对两个不同翻译单元的实验与包含守卫的目的无关。 它没有展示任何东西。 它甚至没有远程关系。

为了利用包含保护,您必须将(显式或隐式)同一个头文件两次包含到一个实现文件中。

其次,仅仅因为某些头文件没有包含保护并且仅仅因为您将该头文件两次包含在同一个翻译单元中并不意味着它一定会触发错误。 为了导致错误,标题必须包含特定“不可重复”类型的声明。 并非每个标题都包含此类违规声明。 在这个意义上,并不是每一个声明都是冒犯的。

您的bar.h (如发布的)实际上是无害的。 正式地,您不需要在bar.h包含守卫。 它只有一个函数声明,可以在一个翻译单元中重复多次。 因此,多次包含此标头不会导致错误。

但是将类似的内容添加到您的bar.h

struct SomeStruct
{
  int i;
};

然后在同一个实现文件中只包含两次,最终会出现错误。 这个错误是包含守卫旨在防止的。 该语言禁止在同一翻译单元中重复相同结构类型的完整声明。

包含保护通常无条件地放置在头文件中。 我很确定,它们也存在于<stdio.h><string.h>中。 目前尚不清楚您为什么声称这些标题“包含在没有包含保护的情况下”。 你检查过这些文件吗? 无论如何,您对两个不同翻译单元的实验无论如何都没有证明任何相关的内容。

回答2

重复声明不是问题; 重复(类型)定义是。 如果bar.h标头包含,例如:

enum FooBar { FOO, BAR, BAZ, QUX };

然后在单个 TU(翻译单元 - 源文件加上包含的标题)中包含两次通常会产生错误。

此外,多重包含场景不是您所展示的。 可能导致问题的原因如下,假设头文件中没有头保护:

  • bar.h

     enum FooBar { FOO, BAR, BAZ, QUX }; void somefunc(char str[]);
  • quack.h

     #include "bar.h" extern enum FooBar foobar_translate(const char *str);
  • main.c

     #include "bar.h" #include "quack.h" …

请注意,GCC 有一个选项-Wredundant-decls来标识冗余声明 - 同一声明出现多次(通常来自多个文件,但如果同一声明在单个文件中出现两次)。

在 C11 之前,您不能重复typedef (在文件范围内;您总是可以在块范围内隐藏外部typedef )。 C11 放宽了该约束:

§6.7 声明

¶3 如果标识符没有链接,则该标识符的声明(在声明符或类型说明符中)不得超过一个具有相同作用域和相同名称空间的声明,但以下情况除外:

  • 可以重新定义 typedef 名称以表示与当前相同的类型,前提是该类型不是可变修改的类型;
  • 标签可以按照 6.7.2.3 中的规定重新声明。

但是,您仍然不能在 TU 的单个范围内两次定义结构类型,因此符号如下:

typedef struct StructTag { … } StructTag;

必须用头部防护装置保护。 如果您使用不透明(不完整)类型,则不会遇到此问题:

typedef struct StructTag StructTag;

至于为什么可以包含标准标题,那是因为标准要求您可以:

§7.1.2 标准标题

¶4 标准标题可以以任何顺序包含; 每个都可以在给定的范围内多次包含,与只包含一次没有什么不同,除了包含<assert.h>的效果取决于NDEBUG的定义(见 7.2)。 如果使用,标头应包含在任何外部声明或定义之外,并且应首先包含在对其声明的任何函数或对象或其定义的任何类型或宏的第一次引用之前。 然而,如果在多个头中声明或定义了一个标识符,则第二个和随后的相关头可以包含在对标识符的初始引用之后。 程序不应有任何名称与在包含标题之前或扩展标题中定义的任何宏时当前定义的关键字词法相同的宏。

使用标题防护可以让您的标题符合标准标题所满足的相同标准。

另请参阅有关一般主题的其他谩骂(答案),包括:

  • 我应该在标题中使用 #include
  • 我如何使用 extern 在源文件之间共享变量 - 该信息是我在标题保护部分中的大量答案中的一种公平方式。
  • 重复 typedef — 在 C 中无效但在 C++ 中有效
  • 如何在C中链接多个实现文件
  • 链接静态库——包含一个脚本chkhdr ,我用它来检查头文件的幂等性和自包含性。
回答3

您的代码中没有错误的原因是您的头文件正在声明但未定义somefunc() 。 对某事的多次声明是可以的,只要它们不是定义——编译器可以接受看到多次声明的东西(当然,只要声明是兼容的)。

一般来说,需要使用include保护来避免头文件之间的循环依赖,比如

  • 报头A和报头B在某些情况下相互包含。 至少在其中一个头文件中需要包含保护以防止预处理器中的无限循环。
  • 头文件 A 包含头文件 B,因为它依赖于其中的定义(例如,内联函数、 typedef ),但其他头文件或编译单元在不同情况下可能包括头文件 A、头文件 B 或两者。 需要包含保护以防止编译单元中包含这两个头文件的多个定义。 至少,包含定义的头文件需要有一个包含保护。

由于头文件可以以任何顺序相互包含,因此上述问题可能会变得非常复杂。

防止某些类型的多重定义是上述的副作用,但不是包含守卫的主要目的。

尽管如此,我处理头文件的经验法则是“在所有头文件中使用包含保护,除非我有特别的理由不这样做”。 通过这样做,避免了与不提供包含保护相关的所有潜在问题。 需要避免包含保护的情况(例如标头声明或定义不同的东西,依赖于编译单元中定义/未定义的宏)在实践中相对较少。 而且,如果您正在使用需要这些东西的技术,您应该已经知道您不应该在受影响的标头中使用包含保护。

回答4

为什么? 因为:

int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);
int char_to_int(char* value, int *res);

int char_to_int(char* value, int *res)
{
    // do something
}

函数原型不会出错,它们是相同的并且函数

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 何时使用包含守卫或 #pragma once C++ [关闭](When to use include guards or #pragma once C++ [closed])
    问题 关闭。 这个问题是基于意见的。 它目前不接受答案。 想改善这个问题吗? 更新问题,以便通过编辑这篇文章用事实和引文来回答问题。 6年前关闭。 改进这个问题 在每个头文件中使用您选择的一个/两个包含守卫和#pragma once ,或者仅使用诸如类声明之类的内容是一种好习惯吗? 我很想把它放在每个头文件中,但我担心它是不需要的,只会增加编译时间。 什么是好的做法或常见的做法? 让我澄清一下:我理解两者之间的区别。 我在问程序员是根据经验在每个文件中使用它还是只在需要它的文件中使用它。 回答1 总结 Galik 的评论和我的理解: 包含保护应该放在每个头文件中,以防将来发生冲突。 此外,编译器处理包含守卫所花费的时间很短,这将使编译更快,因为不需要处理额外的头文件。 回答2 #pragma once是特定于编译器的,而正常的包含保护定义,应该适用于任何 C++ 预处理器。 因此为了便携起见,始终坚持“ye good old”包括守卫成语。 使用包含保护对于防止代码中出现多个符号声明错误至关重要。 您不应该担心 C++ 预处理器如何处理这些假设或含义(现代预处理器已经非常优化以有效地执行此操作)。 回答3 如果您希望您的代码可移植到所有 C++ 编译器,您将需要使用包含守卫。 如果您觉得您使用的编译器低劣并且可以从#pragma once的使用中受益,您还可以添加此 pragma
  • C++中double include守卫的使用(The use of double include guards in C++)
    问题 所以我最近在我工作的地方进行了一次讨论,在讨论中我质疑使用双包含保护而不是单个保护。 我所说的双重保护如下: 头文件,“header_a.hpp”: #ifndef __HEADER_A_HPP__ #define __HEADER_A_HPP__ ... ... #endif 当在头文件或源文件中的任何位置包含头文件时: #ifndef __HEADER_A_HPP__ #include "header_a.hpp" #endif 现在我明白在头文件中使用保护是为了防止多次包含一个已经定义的头文件,它很常见并且有据可查。 如果已经定义了宏,则整个头文件被编译器视为“空白”并防止双重包含。 足够简单。 我不明白的问题是在#include "header_a.hpp"周围使用#ifndef __HEADER_A_HPP__和#endif 。 同事告诉我,这为夹杂物增加了第二层保护,但如果第一层绝对起作用(或确实起作用?),我看不出第二层是如何有用的。 我能想到的唯一好处是它完全阻止了链接器费心寻找文件。 这是为了缩短编译时间(没有提到这是一个好处),还是这里有我没有看到的其他工作? 回答1 我很确定添加另一个包含保护是一种不好的做法,例如: #ifndef __HEADER_A_HPP__ #include "header_a.hpp" #endif 以下是一些原因:
  • 关于包含带有警卫的头文件(about include header file with guards)
    问题 我正在阅读一本关于应用 C++ 的书。 包含保护将防止在编译源文件期间多次包含头文件。 您的符号名称应该是唯一的,我们建议根据文件名称选择名称。 例如,我们的文件 cache.h 包含这个包含保护。 #ifndef _cache_h_ #define _cache_h_ ... #endif // _cache_h_ Lakos 描述了使用冗余包含保护来加速编译。 见[Lakos96]。 对于大型项目,打开每个文件需要时间,才发现包含保护符号已经定义(即文件已经被包含)。 对编译时间的影响可能是巨大的,当仅使用标准包含保护时,Lakos 显示编译时间可能增加 20 倍。 [Lakos96]:大型 C++ 软件设计。 我没有 Lakos96 参考书来参考概念,所以在这里寻求帮助。 我对上述文字的问题是 作者所说的“对于大型项目,打开每个文件需要时间,才发现包含保护符号已经定义”是什么意思? 作者所说的“何时使用标准包含守卫”是什么意思? 感谢您的时间和帮助。 回答1 来自 C++ 编码标准(Sutter、Alexandrescu) 许多现代 C++ 编译器会自动识别头文件保护(参见条款 24),甚至不会两次打开同一个头文件。 有些还提供预编译头,这有助于确保经常使用、很少更改的头不会经常被解析 因此,我认为这些建议已经过时(除非您仍在使用一些非常过时的编译器)。 至于你的问题:
  • C包括守卫到底是做什么的?(What exactly do C include guards do?)
    问题 我对C中的包含卫士有一个疑问。我已经读了一些书,但希望能得到一些澄清。 假设我有一个带有函数定义的头文件“ header.h”。 #ifndef HEADER_FILE #define HEADER_FILE int two(void){ return 2; } #endif 该头文件具有包含保护。 但是,我对#define HEADER_FILE实际在做什么感到困惑。 假设我忘记了include防护,完全忽略添加'#define HEADER_FILE'对我来说是完全合法的。 所以我的问题是:定义HEADER_FILE时,我们到底在做什么? 我们在定义什么? 并且为什么还可以忘记包含保护,在这种情况下我们也可以忘记添加#define HEADER_FILE? 任何帮助表示赞赏! 回答1 这是一个预处理器宏。 所有这些都是预处理程序语法,基本上说,如果尚未定义此宏,则对其进行定义并包括#ifndef和#endif之间的所有代码。 它的作用是防止多次包含文件,这可能会导致代码出现问题。 你的问题: 并且为什么还可以忘记包含保护,在这种情况下我们也可以忘记添加#define HEADER_FILE? 可以忘记它,因为没有它它仍然是合法的C代码。 如果没有逻辑说明为什么不应该这样做,则预处理器会在文件编译之前对其进行处理,并在最终程序中包含指定的代码。 这只是一种常见的做法
  • #ifdef/#define Include-Guard 之前的#include 好吗?(Is an #include before #ifdef/#define Include-Guard okay?)
    问题 我总是将#include放在#ifdef / #define Include-Guard 之后。 现在我的 IDE(Qt Creator)的重构机制把它放在 Include-Guard 之前,例如 #include "AnotherHeader.h" #ifndef MYHEADER_H #define MYHEADER_H 这会导致任何问题还是我可以这样离开? 回答1 如果有问题的标题本身包含保护,您就不会遇到问题。 将它放在包含守卫中可能仍会加快编译速度。 编译器看不到的东西需要更少的时间来编译,即使它没有产生任何错误。 回答2 虽然不太常见,但我认为这被认为是可以接受的,但要注意:如果你有循环#include ,你的包含通常会永远包含彼此(直到预解析器抱怨达到最大包含深度)。 在包含守卫之后的#include不会发生这种情况。 (循环#include在任何情况下都不会被认为是好的样式,但如果仍然使用它,它可能会在包含守卫之后与#include一起使用,但肯定不会与#include在它们之前的一起使用。 回答3 只需检查一下,会发生什么。 让我们假设,两个不同的标头使用MyHeader.h 。 无条件包含AnotherHeader.h 包含保护允许加载头文件的其余部分。 下一次: AnotherHeader.h再次被无条件包含包含保护防止加载头文件的其余部分。
  • 多个 canActivate 守卫都在第一次失败时运行(Multiple canActivate guards all run when first fails)
    问题 我有一条带有两个canActivate守卫( AuthGuard和RoleGuard )的路线。 第一个( AuthGuard )检查用户是否登录,如果没有,则重定向到登录页面。 第二个检查用户是否定义了允许查看页面的角色,如果没有,则重定向到未经授权的页面。 canActivate: [ AuthGuard, RoleGuard ] ... export class AuthGuard implements CanActivate { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> { ... this.router.navigate(['/login']); resolve(false); } export class RoleGuard implements CanActivate { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> { ... this.router.navigate(['/unauthorized']); resolve(false); } 问题是当我访问路由但我没有登录时
  • 包括守卫风格,C++(Include guard style, C++)
    问题 我有一个 .h 文件,其中包含几个类定义。 我想在这个文件中使用 C++ 的包含保护; 但是,我想知道使用包含守卫的哪种方式被认为是正确的/正确的? 一名守卫保护一切 #ifndef FOO_BAR #define FOO_BAR class Foo { }; class Bar { }; #endif 或多个单独的警卫。 #ifndef FOO #define FOO class Foo { }; #endif #ifndef BAR #define BAR class Bar { }; #endif 回答1 它们是包含守卫,防止文件的双重包含。 所以它们应该为每个文件定义一次,而不是每个类或函数或其他任何东西。 回答2 您是否考虑过使用 #pragma once ? 大多数现代编译器都支持它。 #pragma 曾经是一个安全的包含守卫吗?
  • Angular 的 canLoad 和 canActivate 的区别?(Difference between Angular's canLoad and canActivate?)
    问题 canLoad和canActivate什么canActivate ? export interface Route { path?: string; pathMatch?: string; matcher?: UrlMatcher; component?: Type<any>; redirectTo?: string; outlet?: string; canActivate?: any[]; canActivateChild?: any[]; canDeactivate?: any[]; canLoad?: any[]; data?: Data; resolve?: ResolveData; children?: Routes; loadChildren?: LoadChildren; } 我什么时候应该使用其中的哪一个? 回答1 canActivate用于防止未经授权的用户访问某些路由。 有关更多信息,请参阅文档。 canLoad用于防止应用程序在用户未经授权的情况下延迟加载整个模块。 有关更多信息,请参阅下面的文档和示例。 { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule', canLoad: [AuthGuard] }, 使用此代码,仅当 AuthGuard 返回true
  • 为什么在工作后不包括警卫或编译指示?(Why aren't include guards or pragma once working?)
    问题 我正在编译一些依赖于包含守卫来防止对象和函数的多个定义的代码,但是 Visual Studio 2008 给了我有多个定义的链接错误。 我不明白为什么,因为我以前使用过与此非常相似的代码并且它没有引起问题。 我一定在做一些愚蠢的事情,但我不知道那是什么。 我还尝试取出包含守卫并使用 #pragma 一次,但我遇到了相同的链接错误。 我应该检查什么? 回答1 如果它们是链接器错误,最可能的原因可能是标头中定义的非内联函数。 如果在包含在多个源文件中的头中有一个非内联函数,它将在每个源文件(“翻译单元”)中定义,因此该函数将被定义多次,因此多重定义错误。 回答2 如果您遇到链接器错误...您确定您不是 1) 实际上在代码中定义了两次函数,还是 2) 尝试做一些愚蠢的事情,例如#include源文件(而不是头文件)? 回答3 这也可能是由于使用了来自其他库链接的不同版本的 cstd 库。检查 c++/代码生成部分并确保所有项目都使用相同的设置。
  • #pragma一次vs包括守卫吗? [复制](#pragma once vs include guards? [duplicate])
    问题 这个问题已经在这里有了答案: #pragma是否曾经是安全的门卫? (14个回答) 1年前关闭。 我正在开发一个仅在Windows上运行并在Visual Studio下进行编译的代码库(它与excel紧密集成,因此不会在任何地方使用)。 我想知道我是否应该使用传统的包含卫兵,还是将#pragma once用于我们的代码#pragma once 。 我认为让编译器#pragma once处理#pragma once会产生更快的编译,并且在复制和粘贴时不太容易出错。 它也不太丑陋;) 注意:为了获得更快的编译时间,我们可以使用Redundant Include Guards,但这在包含文件和包含文件之间增加了紧密的联系。 通常没关系,因为后卫应该基于文件名,并且仅在需要更改包含名的情况下才会更改。 回答1 我认为这不会对编译时间产生重大影响,但是#pragma once在各个编译器中得到很好的支持,但实际上并不是标准的一部分。 预处理器可能会更快一些,因为它更容易理解您的确切意图。 #pragma once不太容易出错,而且键入的代码也更少。 为了加快编译时间,只要可以,就直接声明而不是包含在.h文件中。 我更喜欢#pragma once使用#pragma once 。 有关使用这两种方法的可能性,请参阅此Wikipedia文章。 回答2 我只是想补充一下这个讨论
  • 在 C++ 中包含两次头文件(including a header file twice in c++)
    问题 如果我在我的文件中两次包含iostream或任何其他头文件会发生什么? 我知道编译器不会抛出错误。 代码会被添加两次还是内部会发生什么? 当我们包含一个头文件时实际发生了什么? 回答1 包含保护防止文件的内容被编译器实际看到两次。 包含保护基本上是头文件开头和结尾处的一组预处理器的条件指令: #ifndef SOME_STRING_H #define SOME_STRING_H //... #endif 现在,如果您两次包含该文件,则第一次循环宏SOME_STRING_H未定义,因此编译器会处理和查看文件的内容。 但是,由于#ifdef之后的第一件事是#define , SOME_STRING_H定义了SOME_STRING_H并且下一次编译器看不到头文件的内容。 为了避免冲突,包含保护中使用的宏的名称取决于头文件的名称。 回答2 头文件是简单的野兽。 当你#include <header>发生的所有事情是header的内容基本上被复制粘贴到文件中。 为了阻止头文件被多次include guards ,使用了include guards ,这就是为什么在大多数头文件中你会看到类似于 #ifndef SOME_HEADER_FILE_GUARD #define SOME_HEADER_FILE_GUARD //Contents of Header #endif 回答3
  • 将参数传递给路由守卫(Pass parameter into route guard)
    问题 我正在开发一个应用程序,它有很多角色,我需要使用警卫来阻止导航到基于这些角色的应用程序部分。 我意识到我可以为每个角色创建单独的守卫类,但宁愿有一个我可以以某种方式传递参数的类。 换句话说,我希望能够做类似的事情: { path: 'super-user-stuff', component: SuperUserStuffComponent, canActivate: [RoleGuard.forRole('superUser')] } 但是因为你传递的只是你的守卫的类型名称,所以想不出办法来做到这一点。 我是否应该咬紧牙关,为每个角色编写单独的保护类,并打破我拥有单一参数化类型的优雅错觉? 回答1 您可以这样做,而不是使用forRole() : { path: 'super-user-stuff', component: SuperUserStuffComponent, canActivate: RoleGuard, data: {roles: ['SuperAdmin', ...]} } 并在您的 RoleGuard 中使用它 canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean> | Promise<boolean> | boolean {
  • 可以使用静态变量来初始化/注册变量吗?(Is it ok to use a static variable to initialize/register variables?)
    问题 语言:C++ 工具包:Qt4 我使用的工具包有一个名为int QEvent::registerEventType()的静态方法来注册我自己的事件类型。 当我对这个QEvent子类化时,我需要提供基类这个值。 QEvent::QEvent(int type) 。 在应用程序启动之前使用静态变量来调用它是否可以? 考虑以下: //This is all in my .cpp file static int myEventType; //This will contain my registered type /*If I create a static instance of this class the constructor gets called before the main() function starts. */ class DoRegisterMyEventType { public: DoRegisterMyEventType() { myEventType = QEvent::registerEventType(); } }; static DoRegisterMyEventType doRegisterMyEventType; //Here is the constructor for MyEvent class which inherits QEvent
  • 斯威夫特:守卫让vs如果让(Swift: guard let vs if let)
    问题 我一直在阅读有关Swift中Optional的内容,并且看到了一些示例,其中if let来检查Optional是否持有一个值,并且在有情况的情况下–使用未包装的值进行操作。 但是,我已经看到在Swift 2.0中,关键字guard let被广泛使用。 我想知道是否已经从Swift 2.0中删除了if let还是仍然可以使用它。 我是否应该更改包含if let来guard let ? 回答1 if let与guard let服务于相似但截然不同的目的。 的“其他人”案guard必须退出当前的范围。 通常,这意味着它必须调用return或中止程序。 guard用于提供早期返回,而无需嵌套其余功能。 if let嵌套其作用域,并且不需要任何特殊的内容。 它可以return还是不return 。 通常,如果if-let块将成为该函数的其余部分,或者它的else子句中将有return或中止,那么您应该改用guard 。 这通常意味着(至少以我的经验),如果有疑问,通常最好选择guard 。 但是在很多情况下, if let仍然是合适的。 回答2 守卫可以提高清晰度 当您使用Guard时,您对Guard的成功寄予更高的期望,如果它没有成功,那么您只想提早退出范围是很重要的。 就像您警惕地查看文件/图像是否存在,数组是否为isEmpty。 func icon() -> UIImage {
  • vue笔记 (十四) vue-router (4):导航守卫guard、组件缓存keep-alive
    导航守卫 导航守卫主要用来监听路由的进入和离开,vue-router 提供了三类守卫方式, 全局设置,路由设置,组件内部设置。 全局设置 全局前置守卫 const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { next() }) 三个参数解析: to: 即将要进入的目标路由对象 from: 当前导航即将要离开的路由对象 next: 调用该方法后,才能进入下一个钩 next(): 进行管道中的下一个钩子next(false): 中断当前的导航,如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
  • Haskell 守卫是如何评估的?(How are Haskell guards evaluated?)
    问题 我正在做 99 Haskell 问题,在其中一个解决方案中,我遇到了以下代码: pack' [] = [] pack' [x] = [[x]] pack' (x:xs) | x == head h_p_xs = (x:h_p_xs):t_p_hs | otherwise = [x]:p_xs where p_xs@(h_p_xs:t_p_hs) = pack' xs 我想知道什么时候在第一个守卫中调用 pack' ,这是否是 Haskell 代码中引用函数调用返回的列表的头部和尾部的常见模式。 在任何递归级别是否有多次调用 pack' ,这是一个快速的解决方案吗? 回答1 我想知道什么时候会在第一个守卫中叫“包” 防护x == head h_p_xs力的评价h_p_xs ,这会触发递归调用。 如果这是 Haskell 代码中的常见模式,用于引用从函数调用返回的列表的头部和尾部。 我认为这是一个很常见的模式。 您可能还会发现使用case pack' xs of ...或let ... = pack' xs in ... 。 请注意,只要找到空列表,将let或where与诸如h_p_xs:t_p_xs类的模式h_p_xs:t_p_xs将导致运行时错误。 此代码小心地确保递归调用不会返回一个空列表。 在任何递归级别是否有多次调用 pack' 说到迂腐,Haskell
  • Swift 守卫还调用了具有 NULL 值的字典键(Swift guard else called on dictionary key with NULL value)
    问题 如果我有一个从包含以下内容的 NSNotification 返回的字典 print(notificationObj.object) Optional({ age = "<null>"; names = ( David ); }) 然后在尝试将其分配给变量时调用保护 else : guard let categories = notificationObj.object as? [String:[String]] else { // Gets to here return } 我如何处理字典键为空的情况。 回答1 你的字典确实包含... Optional({ age = "<null>"; names = ( David ); }) ... 和 ... age = ... is String = String (值是单个String ), names = ( ... )是String = [String] (值是String的数组)。 您不能将其强制转换为[String:[String]]因为第一对不适合此类型。 这就是为什么你的guard语句命中else的原因。 很难回答你的问题。 Dictionary 包含names ,你想要categories , names键确实包含David ,这看起来不像 category ,......至少你知道为什么guard命中else 。
  • 标题守卫和编译指示一次 [重复](Header guards and pragma once [duplicate])
    问题 这个问题在这里已经有了答案: #pragma once vs 包含守卫? [重复] (13 个回答) 8年前关闭。 1.我看到很多地方,Header guards 和 pragma once 也以特定的顺序一起使用(顺序真的重要吗?) 2.另一个疑问是默认情况下每当VS IDE生成新类文件时,它都会将#pragma一次放入实现文件(.cpp)。 这真的是必需的吗? #ifndef MYHEADER_H #define MYHEADER_H #pragma once //my set of includes 哪个是标题保护或阻止多个包含的正确方法? 回答1 #pragma once 是非标准的,尽管许多流行的编译器/预处理器都支持。 请参阅 #pragma 曾经是安全的包含守卫吗? #ifndef MYHEADER_H #define MYHEADER_H #endif // ndef MYHEADER_H 保证适用于所有 C++ 编译器/预处理器。 同时使用两者是没有意义的。 回答2 “#pragma once” 是特定于编译器的,可能不可移植。 "#ifndef/#define/#endif" 更便携,适用于所有预处理器。
  • 守卫 --listen-on with vagrant(Guard --listen-on with vagrant)
    问题 我正在尝试将守卫的--listen-on选项与此处概述的 vagrant 一起使用,但我无法让它工作。 如果我将config.vm.network :forwarded_port, guest: 4000, host: 4000到我的Vagrantfile并随后尝试使用listen -f 127.0.0.1:4000开始侦听,我会收到错误消息: Broadcaster.initialize: Address already in use - bind(2) for "127.0.0.1" port 4000 。 如果我尝试开始听然后开始 vagrant,vagrant 会发出类似的抱怨: Vagrant 无法转发此 VM 上的指定端口,因为它们会与其他已在侦听这些端口的应用程序发生冲突。 转发到 4000 的端口已在主机上使用。 所以我在忽略Vagrantfile的端口 4000 转发时尝试了其他一些东西: 如果我在Vagrantfile省略了端口 4000 转发,那么我可以成功地使用listen -f 127.0.0.1:4000开始监听。 但是当我在我的流浪来宾中运行guard -o "10.0.2.2:4000" -w "/home/me/my_project/"时,当文件更改时,guard 不会做任何事情。 添加-v标志的listen电话显示,改变被拾起正确的主机上。
  • 序言中的保护条款?(Guard clauses in prolog?)
    问题 它们存在吗? 它们是如何实施的? SWI-Prolog 的协程谓词( freeze 、 when 、 dif等)具有守卫的功能。 它们如何适应首选的 Prolog 编程风格? 我对逻辑编程(使用 Prolog 和全部)非常陌生,并且对它不是纯粹的声明性这一事实感到有些困惑,即使在非常简单的情况下也需要程序考虑(请参阅有关使用 \== 或 dif 的问题)。 我错过了什么重要的东西吗? 回答1 首先是一个术语问题:在任何情况下, freeze/2 、 when/2和dif/2都不被称为守卫。 Guards 出现在 CHR 等扩展中,或 GHC(日文链接)或其他并发逻辑编程语言等相关语言中; 您甚至(在某些限制下)可能会考虑以下形式的条款 头:-守卫, !, ... 作为包含守卫和剪切的子句在这种情况下将被称为提交。 但没有一个适用于上述原语。 Guards 的灵感来自 Dijkstra 于 1975 年的 Guarded Command Language。 freeze(X, Goal) (最初称为geler )与when(nonvar(X), Goal)并且它们在声明上都等效于Goal 。 与守卫的功能没有直接关系。 但是,当与 if-then-else 一起使用时,您可能会实现这样的保护。 但这是非常不同的。 一段时间以来, freeze/2和类似的结构被认为是改进