精华内容
下载资源
问答
  • 上篇我们学到Blockly中积木的标准元素类型,这篇我们将自定义积木,并将积木添加到工具箱中...1. JSON定义积木Blockly有两种定义积木的方法:JSON对象和JavaScript函数,JSON格式无法直接定义高级功能。在Web上,使...

    上篇我们学到Blockly中积木的标准元素类型,这篇我们将自定义积木,并将积木添加到工具箱中。

    定义积木需要描述积木的外观和行为,包括文本,颜色,形状以及它可以连接的其他积木。积木的定义有两种方法,一种编写json或JS代码,另一种使用开发者工具生成代码。

    1. JSON定义积木

    Blockly有两种定义积木的方法:JSON对象和JavaScript函数,JSON格式无法直接定义高级功能。在Web上,使用该initJson函数加载JSON格式。也可以在Blockly网页中混合使用这两种格式。最好尽可能使用JSON定义积木,并将JavaScript用于JSON不支持的积木定义部分。

    积木颜色

    积木的主要颜色由JSON colour属性, block.setColour(..)函数或使用主题定义积木样式定义。

    {"colour": 160}

    积木卡合

    用户可以使用nextStatement(后置连接)和 previousStatement(前置连接)连接器创建积木序列。在Blockly的标准布局中,这些连接位于顶部和底部,并且积木垂直堆叠。 后置连接,nextStatement:null

    5b6d594665f232c14dedd523883fc9e9.png

    前置连接,previousStatement:null

    084c1b28c4691a8921a94382590fa554.png

    积木输出

    积木具有单个输出,输出连接到值输入。具有输出的积木通常称为值积木。 积木输出,output:Type

    555c8738b7921a59115baae44565175a.png

    积木输入

    积木具有一个或多个输入,其中每个输入是可以在连接中结束的标签和字段序列。有三种类型的输入,匹配卡合类型:

    • 值输入(Value input):卡合到一个积木的输出。加法,减法都是具有两个值输入的积木;
    • 声明输入(Statement input):卡合到前一个的语句积木。 while循环的嵌套部分输入积木;
    • 虚拟输入(Dummy input):没有积木卡合。当积木配置为使用外部值输入时,类似于换行符。

    JSON定义积木被构造为变量字符串的序列( message0,message1, ...),其中每一变量标记( %1, %2, ...)是一个元素或一个输入参数,这正好匹配的JSON argsN数组中。

    {
      "message0": "set %1 to %2",
      "args0": [
        {
          "type": "field_variable",
          "name": "VAR",
          "variable": "item",
          "variableTypes": [""]
        },
        {
          "type": "input_value",
          "name": "VALUE"
        }
      ]
    }

    70470b2281bfb2094b3a2a9f4213c98f.png

    每个消息字符串与args相同数字的数组配对。例如, message0顺其自在args0。插值标记( %1,, %2......)指的是args数组的项目。每个对象都有一个 type字符串,type字符串即为元素类型。

    积木提示

    当用户将鼠标悬停在积木上时,将提供即时帮助。如果文本很长,它将自动换行。 {"tooltip": "Tooltip text."}

    积木帮助网址

    积木可以有一个与之关联的帮助页面。通过右键单击积木并从上下文菜单中选择“帮助”。如果此值为则null则菜单将显示为灰色。 {"helpUrl": "https://en.wikipedia.org/wiki/For_loop"}

    积木事件

    积木可以更改监听函数,通过使用函数调用setOnChange来添加该函数,工作空间的任何更改会调用函数。主要用于设置积木的警告文本或工作区外的通知。

    2. 开发者工具

    Blockly Developer Tools是一个基于Web的开发人员工具,可自动执行部分Blockly配置过程,包括创建自定义积木,构建工具箱以及配置工作空间。

    使用该工具的Blockly开发人员流程包括三个部分: 使用Block Factory和Block Exporter创建自定义积木 使用Workspace Factory构建工具箱和默认工作空间 * 使用Workspace Factory配置工作空间

    Block Factory(积木设计)

    "Block Factory"可自定义的创建积木定义和代码生成器。在此选项卡上,您可以轻松创建,修改和保存自定义积木。

    7f235d63102897c07ed568441b205797.png

    Block Library(库管理)Import Block Library(导入)Download Block Library(导出) 积木库管理,每个库对应一个唯一的名称,积木将保存到浏览器的本地存储中。清除浏览器的本地存储将删除您的积木。要无限期保存积木,必须下载库。积木库将作为XML文件下载,要想使用积木,需要将此积木导入进来。导入积木库会替换当前积木,因此您最好导出当前库。

    7342ffb70a53d410ef58470054ff659c.png

    07c8db0869612614cfe8c57e01fd955e.png

    Input:输入类型,详见JSON定义积木输入 Field:元素,详见上篇文章谈到的10中标准输入类型 Type:输入或输出类型,弱对象类型 Colour:积木颜色

    Block Exporter(导出积木)

    设计积木后,需要导出积木定义和代码生成器,以便在应用程序中使用它们。存储在积木库中的每个积木都将显示在积木选择器中。单击积木以选择或取消选择它以进行导出。

    3e7abb2fa256190afda3d3054eaffcfa.png

    Workspace Factory(工作空间设计)

    Workspace Factory可以配置工具箱和工作空间中的默认积木集,可以使用“Toolbox”和“Workspace”按钮进行切换设置。

    60b2845967fe53b602a11c6a4dda16ec.png

    左侧为标准工具箱,Block Library分类为浏览器中的积木库,右侧工具箱是生成的工具箱,工具箱的生成由

    9ca8a3289877515cd80d67c9d5fce61f.png

    控制,“+、-” 号可添加分类或积木到工具箱中,上下箭头控制工具箱的类别顺序。

    9c3092d9eb7c9d7747f9bdeb04e18a4f.png

    工具箱生成后,可以对工作空间进行配置,配置的是Blockly.inject的第二个option参数。

    展开全文
  • error C2601: “Managers::AddChess”: 本地函数定义是非法的 以及 IntelliSense: 不能在成员函数 "Managers::AddChess" 的类外部重新声明该函数
    有可能是前面少了一个大括号,导致你后面定义函数时被前面的函数包了进去!
    
    展开全文
  • trait 告诉 Rust 编译器某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式定义共享的行为。...trait 定义是一种将方法签名组合起来的方法,目的是定义一个实现某些目的所...

    trait 告诉 Rust 编译器某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式定义共享的行为。可以使用 trait bounds 指定泛型是任何拥有特定行为的类型。

    74a4ad154227c25322fa839a6c9e7aec.png

    定义 trait

    一个类型的行为由其可供调用的方法构成。如果可以对不同类型调用相同的方法的话,这些类型就可以共享相同的行为了。trait 定义是一种将方法签名组合起来的方法,目的是定义一个实现某些目的所必需的行为的集合。

    例如,这里有多个存放了不同类型和属性文本的结构体:结构体 NewsArticle 用于存放发生于世界各地的新闻故事,而结构体 Tweet 最多只能存放 280 个字符的内容,以及像是否转推或是否是对推友的回复这样的元数据。

    我们想要创建一个多媒体聚合库用来显示可能储存在 NewsArticle 或 Tweet 实例中的数据的总结。每一个结构体都需要的行为是他们是能够被总结的,这样的话就可以调用实例的 summarize 方法来请求总结。示例 10-12 中展示了一个表现这个概念的 Summary trait 的定义:

    文件名: src/lib.rs

    pub trait Summary {    fn summarize(&self) -> String;}

    示例 10-12:Summary trait 定义,它包含由 summarize 方法提供的行为

    这里使用 trait 关键字来声明一个 trait,后面是 trait 的名字,在这个例子中是 Summary。在大括号中声明描述实现这个 trait 的类型所需要的行为的方法签名,在这个例子中是 fn summarize(&self) -> String。

    在方法签名后跟分号,而不是在大括号中提供其实现。接着每一个实现这个 trait 的类型都需要提供其自定义行为的方法体,编译器也会确保任何实现 Summary trait 的类型都拥有与这个签名的定义完全一致的 summarize 方法。

    trait 体中可以有多个方法:一行一个方法签名且都以分号结尾。

    184a643dfbbf5061a71f510f47f1b95f.png

    为类型实现 trait

    现在我们定义了 Summary trait,接着就可以在多媒体聚合库中需要拥有这个行为的类型上实现它了。示例 10-13 中展示了 NewsArticle 结构体上 Summary trait 的一个实现,它使用标题、作者和创建的位置作为 summarize 的返回值。对于 Tweet 结构体,我们选择将 summarize 定义为用户名后跟推文的全部文本作为返回值,并假设推文内容已经被限制为 280 字符以内。

    文件名: src/lib.rs

    pub struct NewsArticle {    pub headline: String,    pub location: String,    pub author: String,    pub content: String,}impl Summary for NewsArticle {    fn summarize(&self) -> String {        format!("{}, by {} ({})", self.headline, self.author, self.location)    }}pub struct Tweet {    pub username: String,    pub content: String,    pub reply: bool,    pub retweet: bool,}impl Summary for Tweet {    fn summarize(&self) -> String {        format!("{}: {}", self.username, self.content)    }}

    示例 10-13:在 NewsArticle 和 Tweet 类型上实现 Summary trait

    在类型上实现 trait 类似于实现与 trait 无关的方法。区别在于 impl 关键字之后,我们提供需要实现 trait 的名称,接着是 for 和需要实现 trait 的类型的名称。在 impl 块中,使用 trait 定义中的方法签名,不过不再后跟分号,而是需要在大括号中编写函数体来为特定类型实现 trait 方法所拥有的行为。

    一旦实现了 trait,我们就可以用与 NewsArticle 和 Tweet 实例的非 trait 方法一样的方式调用 trait 方法了:

    let tweet = Tweet {    username: String::from("horse_ebooks"),    content: String::from("of course, as you probably already know, people"),    reply: false,    retweet: false,};println!("1 new tweet: {}", tweet.summarize());

    这会打印出 1 new tweet: horse_ebooks: of course, as you probably already know, people。

    注意因为示例 10-13 中我们在相同的 lib.rs 里定义了 Summary trait 和 NewsArticle 与 Tweet 类型,所以他们是位于同一作用域的。如果这个 lib.rs 是对应 aggregator crate 的,而别人想要利用我们 crate 的功能为其自己的库作用域中的结构体实现 Summary trait。首先他们需要将 trait 引入作用域。这可以通过指定 use aggregator::Summary; 实现,这样就可以为其类型实现 Summary trait 了。Summary 还必须是公有 trait 使得其他 crate 可以实现它,这也是为什么实例 10-12 中将 pub 置于 trait 之前。

    实现 trait 时需要注意的一个限制是,只有当 trait 或者要实现 trait 的类型位于 crate 的本地作用域时,才能为该类型实现 trait。例如,可以为 aggregator crate 的自定义类型 Tweet 实现如标准库中的 Display trait,这是因为 Tweet 类型位于 aggregator crate 本地的作用域中。类似地,也可以在 aggregator crate 中为 Vec 实现 Summary,这是因为 Summary trait 位于 aggregator crate 本地作用域中。

    但是不能为外部类型实现外部 trait。例如,不能在 aggregator crate 中为 Vec 实现 Display trait。这是因为 Display 和 Vec 都定义于标准库中,它们并不位于 aggregator crate 本地作用域中。这个限制是被称为 相干性(coherence) 的程序属性的一部分,或者更具体的说是 孤儿规则(orphan rule),其得名于不存在父类型。这条规则确保了其他人编写的代码不会破坏你代码,反之亦然。没有这条规则的话,两个 crate 可以分别对相同类型实现相同的 trait,而 Rust 将无从得知应该使用哪一个实现。

    7ffc2769a974a01b718c8bb8a7e69377.png

    默认实现

    有时为 trait 中的某些或全部方法提供默认的行为,而不是在每个类型的每个实现中都定义自己的行为是很有用的。这样当为某个特定类型实现 trait 时,可以选择保留或重载每个方法的默认行为。

    示例 10-14 中展示了如何为 Summary trait 的 summarize 方法指定一个默认的字符串值,而不是像示例 10-12 中那样只是定义方法签名:

    文件名: src/lib.rs

    pub trait Summary {    fn summarize(&self) -> String {        String::from("(Read more...)")    }}

    示例 10-14:Summary trait 的定义,带有一个 summarize 方法的默认实现

    如果想要对 NewsArticle 实例使用这个默认实现,而不是定义一个自己的实现,则可以通过 impl Summary for NewsArticle {} 指定一个空的 impl 块。

    虽然我们不再直接为 NewsArticle 定义 summarize 方法了,但是我们提供了一个默认实现并且指定 NewsArticle 实现 Summary trait。因此,我们仍然可以对 NewsArticle 实例调用 summarize 方法,如下所示:

    let article = NewsArticle {    headline: String::from("Penguins win the Stanley Cup Championship!"),    location: String::from("Pittsburgh, PA, USA"),    author: String::from("Iceburgh"),    content: String::from("The Pittsburgh Penguins once again are the best    hockey team in the NHL."),};println!("New article available! {}", article.summarize());

    这段代码会打印 New article available! (Read more...)。

    为 summarize 创建默认实现并不要求对示例 10-13 中 Tweet 上的 Summary 实现做任何改变。其原因是重载一个默认实现的语法与实现没有默认实现的 trait 方法的语法一样。

    默认实现允许调用相同 trait 中的其他方法,哪怕这些方法没有默认实现。如此,trait 可以提供很多有用的功能而只需要实现指定一小部分内容。例如,我们可以定义 Summary trait,使其具有一个需要实现的 summarize_author 方法,然后定义一个 summarize 方法,此方法的默认实现调用 summarize_author 方法:

    pub trait Summary {    fn summarize_author(&self) -> String;    fn summarize(&self) -> String {        format!("(Read more from {}...)", self.summarize_author())    }}

    为了使用这个版本的 Summary,只需在实现 trait 时定义 summarize_author 即可:

    impl Summary for Tweet {    fn summarize_author(&self) -> String {        format!("@{}", self.username)    }}

    一旦定义了 summarize_author,我们就可以对 Tweet 结构体的实例调用 summarize 了,而 summary 的默认实现会调用我们提供的 summarize_author 定义。因为实现了 summarize_author,Summary trait 就提供了 summarize 方法的功能,且无需编写更多的代码。

    let tweet = Tweet {    username: String::from("horse_ebooks"),    content: String::from("of course, as you probably already know, people"),    reply: false,    retweet: false,};println!("1 new tweet: {}", tweet.summarize());

    这会打印出 1 new tweet: (Read more from @horse_ebooks...)。

    注意无法从相同方法的重载实现中调用默认方法。

    469ee5e03a73d2bccd4323fe187bddc7.png

    trait 作为参数

    知道了如何定义 trait 和在类型上实现这些 trait 之后,我们可以探索一下如何使用 trait 来接受多种不同类型的参数。

    例如在示例 10-13 中为 NewsArticle 和 Tweet 类型实现了 Summary trait。我们可以定义一个函数 notify 来调用其参数 item 上的 summarize 方法,该参数是实现了 Summary trait 的某种类型。为此可以使用 impl Trait 语法,像这样:

    pub fn notify(item: impl Summary) {    println!("Breaking news! {}", item.summarize());}

    对于 item 参数,我们指定了 impl 关键字和 trait 名称,而不是具体的类型。该参数支持任何实现了指定 trait 的类型。在 notify 函数体中,可以调用任何来自 Summary trait 的方法,比如 summarize。我们可以传递任何 NewsArticle 或 Tweet 的实例来调用 notify。任何用其它如 String 或 i32 的类型调用该函数的代码都不能编译,因为它们没有实现 Summary。

    Trait Bound 语法

    impl Trait 语法适用于直观的例子,它不过是一个较长形式的语法糖。这被称为 trait bound,这看起来像:

    pub fn notify(item: T) {    println!("Breaking news! {}", item.summarize());}

    这与之前的例子相同,不过稍微冗长了一些。trait bound 与泛型参数声明在一起,位于尖括号中的冒号后面。

    impl Trait 很方便,适用于短小的例子。trait bound 则适用于更复杂的场景。例如,可以获取两个实现了 Summary 的参数。使用 impl Trait 的语法看起来像这样:

    pub fn notify(item1: impl Summary, item2: impl Summary) {

    这适用于 item1 和 item2 允许是不同类型的情况(只要它们都实现了 Summary)。不过如果你希望强制它们都是相同类型呢?这只有在使用 trait bound 时才有可能:

    pub fn notify(item1: T, item2: T) {

    泛型 T 被指定为 item1 和 item2 的参数限制,如此传递给参数 item1 和 item2 值的具体类型必须一致。

    通过 + 指定多个 trait bound

    如果 notify 需要显示 item 的格式化形式,同时也要使用 summarize 方法,那么 item 就需要同时实现两个不同的 trait:Display 和 Summary。这可以通过 + 语法实现:

    pub fn notify(item: impl Summary + Display) {

    + 语法也适用于泛型的 trait bound:

    pub fn notify(item: T) {

    通过指定这两个 trait bound,notify 的函数体可以调用 summarize 并使用 {} 来格式化 item。

    通过 where 简化 trait bound

    然而,使用过多的 trait bound 也有缺点。每个泛型有其自己的 trait bound,所以有多个泛型参数的函数在名称和参数列表之间会有很长的 trait bound 信息,这使得函数签名难以阅读。为此,Rust 有另一个在函数签名之后的 where 从句中指定 trait bound 的语法。所以除了这么写:

    fn some_function(t: T, u: U) -> i32 {

    还可以像这样使用 where 从句:

    fn some_function(t: T, u: U) -> i32    where T: Display + Clone,          U: Clone + Debug{

    这个函数签名就显得不那么杂乱,函数名、参数列表和返回值类型都离得很近,看起来类似没有很多 trait bounds 的函数。

    010b77fc52cd46617d327e19e1d94da4.png

    返回实现了 trait 的类型

    也可以在返回值中使用 impl Trait 语法,来返回实现了某个 trait 的类型:

    fn returns_summarizable() -> impl Summary {    Tweet {        username: String::from("horse_ebooks"),        content: String::from("of course, as you probably already know, people"),        reply: false,        retweet: false,    }}

    通过使用 impl Summary 作为返回值类型,我们指定了 returns_summarizable 函数返回某个实现了 Summary trait 的类型,但是不确定其具体的类型。在这个例子中 returns_summarizable 返回了一个 Tweet,不过调用方并不知情。

    返回一个只是指定了需要实现的 trait 的类型的能力在闭包和迭代器场景十分的有用,第十三章会介绍它们。闭包和迭代器创建只有编译器知道的类型,或者是非常非常长的类型。impl Trait 允许你简单的指定函数返回一个 Iterator 而无需写出实际的冗长的类型。

    不过这只适用于返回单一类型的情况。例如,这段代码的返回值类型指定为返回 impl Summary,但是返回了 NewsArticle 或 Tweet 就行不通:

    fn returns_summarizable(switch: bool) -> impl Summary {    if switch {        NewsArticle {            headline: String::from("Penguins win the Stanley Cup Championship!"),            location: String::from("Pittsburgh, PA, USA"),            author: String::from("Iceburgh"),            content: String::from("The Pittsburgh Penguins once again are the best            hockey team in the NHL."),        }    } else {        Tweet {            username: String::from("horse_ebooks"),            content: String::from("of course, as you probably already know, people"),            reply: false,            retweet: false,        }    }}

    这里尝试返回 NewsArticle 或 Tweet。这不能编译,因为 impl Trait 工作方式的限制。第十七章的 “为使用不同类型的值而设计的 trait 对象” 部分会介绍如何编写这样一个函数。

    947f8eb2ed27831e1a0252ea2adb2cf3.png

    使用 trait bounds 来修复 largest 函数

    现在你知道了如何使用泛型参数 trait bound 来指定所需的行为。让我们回到实例 10-5 修复使用泛型类型参数的 largest 函数定义!回顾一下,最后尝试编译代码时出现的错误是:

    error[E0369]: binary operation `>` cannot be applied to type `T` --> src/main.rs:5:12  |5 |         if item > largest {  |            ^^^^^^^^^^^^^^  |  = note: an implementation of `std::cmp::PartialOrd` might be missing for `T`

    在 largest 函数体中我们想要使用大于运算符(>)比较两个 T 类型的值。这个运算符被定义为标准库中 trait std::cmp::PartialOrd 的一个默认方法。所以需要在 T 的 trait bound 中指定 PartialOrd,这样 largest 函数可以用于任何可以比较大小的类型的 slice。因为 PartialOrd 位于 prelude 中所以并不需要手动将其引入作用域。将 largest 的签名修改为如下:

    fn largest(list: &[T]) -> T {

    但是如果编译代码的话,会出现一些不同的错误:

    error[E0508]: cannot move out of type `[T]`, a non-copy slice --> src/main.rs:2:23  |2 |     let mut largest = list[0];  |                       ^^^^^^^  |                       |  |                       cannot move out of here  |                       help: consider using a reference instead: `&list[0]`error[E0507]: cannot move out of borrowed content --> src/main.rs:4:9  |4 |     for &item in list.iter() {  |         ^----  |         ||  |         |hint: to prevent move, use `ref item` or `ref mut item`  |         cannot move out of borrowed content

    错误的核心是 cannot move out of type [T], a non-copy slice,对于非泛型版本的 largest 函数,我们只尝试了寻找最大的 i32 和 char。正如第四章 “只在栈上的数据:拷贝” 部分讨论过的,像 i32 和 char 这样的类型是已知大小的并可以储存在栈上,所以他们实现了 Copy trait。当我们将 largest 函数改成使用泛型后,现在 list 参数的类型就有可能是没有实现 Copy trait 的。这意味着我们可能不能将 list[0] 的值移动到 largest 变量中,这导致了上面的错误。

    为了只对实现了 Copy 的类型调用这些代码,可以在 T 的 trait bounds 中增加 Copy!示例 10-15 中展示了一个可以编译的泛型版本的 largest 函数的完整代码,只要传递给 largest 的 slice 值的类型实现了 PartialOrd Copy 这两个 trait,例如 i32 和 char:

    文件名: src/main.rs

    fn largest(list: &[T]) -> T {    let mut largest = list[0];    for &item in list.iter() {        if item > largest {            largest = item;        }    }    largest}fn main() {    let number_list = vec![34, 50, 25, 100, 65];    let result = largest(&number_list);    println!("The largest number is {}", result);    let char_list = vec!['y', 'm', 'a', 'q'];    let result = largest(&char_list);    println!("The largest char is {}", result);}

    示例 10-15:一个可以用于任何实现了 PartialOrd 和 Copy trait 的泛型的 largest 函数

    如果并不希望限制 largest 函数只能用于实现了 Copy trait 的类型,我们可以在 T 的 trait bounds 中指定 Clone 而不是 Copy。并克隆 slice 的每一个值使得 largest 函数拥有其所有权。使用 clone 函数意味着对于类似 String 这样拥有堆上数据的类型,会潜在的分配更多堆上空间,而堆分配在涉及大量数据时可能会相当缓慢。

    另一种 largest 的实现方式是返回在 slice 中 T 值的引用。如果我们将函数返回值从 T 改为 &T 并改变函数体使其能够返回一个引用,我们将不需要任何 Clone 或 Copy 的 trait bounds 而且也不会有任何的堆分配。尝试自己实现这种替代解决方式吧!

    9c0adca608e421262df3f5e6099f6c44.png

    使用 trait bound 有条件地实现方法

    通过使用带有 trait bound 的泛型参数的 impl 块,可以有条件地只为那些实现了特定 trait 的类型实现方法。例如,示例 10-16 中的类型 Pair 总是实现了 new 方法,不过只有那些为 T 类型实现了 PartialOrd trait (来允许比较) Display trait (来启用打印)的 Pair 才会实现 cmp_display 方法:

    use std::fmt::Display;struct Pair {    x: T,    y: T,}impl Pair {    fn new(x: T, y: T) -> Self {        Self {            x,            y,        }    }}impl Pair {    fn cmp_display(&self) {        if self.x >= self.y {            println!("The largest member is x = {}", self.x);        } else {            println!("The largest member is y = {}", self.y);        }    }}

    示例 10-16:根据 trait bound 在泛型上有条件的实现方法

    也可以对任何实现了特定 trait 的类型有条件地实现 trait。对任何满足特定 trait bound 的类型实现 trait 被称为 blanket implementations,他们被广泛的用于 Rust 标准库中。例如,标准库为任何实现了 Display trait 的类型实现了 ToString trait。这个 impl 块看起来像这样:

    impl ToString for T {    // --snip--}

    因为标准库有了这些 blanket implementation,我们可以对任何实现了 Display trait 的类型调用由 ToString 定义的 to_string 方法。例如,可以将整型转换为对应的 String 值,因为整型实现了 Display:

    let s = 3.to_string();

    blanket implementation 会出现在 trait 文档的 “Implementers” 部分。

    trait 和 trait bound 让我们使用泛型类型参数来减少重复,并仍然能够向编译器明确指定泛型类型需要拥有哪些行为。因为我们向编译器提供了 trait bound 信息,它就可以检查代码中所用到的具体类型是否提供了正确的行为。在动态类型语言中,如果我们尝试调用一个类型并没有实现的方法,会在运行时出现错误。Rust 将这些错误移动到了编译时,甚至在代码能够运行之前就强迫我们修复错误。另外,我们也无需编写运行时检查行为的代码,因为在编译时就已经检查过了,这样相比其他那些不愿放弃泛型灵活性的语言有更好的性能。

    这里还有一种泛型,我们一直在使用它甚至都没有察觉它的存在,这就是 生命周期(lifetimes)。不同于其他泛型帮助我们确保类型拥有期望的行为,生命周期则有助于确保引用在我们需要他们的时候一直有效。让我们学习生命周期是如何做到这些的。

    展开全文
  • error C2601: “...”: 本地函数定义是非法的

    万次阅读 多人点赞 2018-05-24 14:06:22
    有可能前面少了一个大括号,导致你后面定义函数时被前面的函数包了进去!
    有可能是前面少了一个大括号,导致你后面定义函数时被前面的函数包了进去!
    展开全文
  • 打开一个别人编好的QT程序...报错一堆,主要是{D:\2017GR_STU\qt\nnn\double alarm\mainwindow.cpp:484: error: C2601: “MainWindow::on_cpButton_clicked”: 本地函数定义是非法的 ..\double alarm\mainwindow.cpp(21
  • 1)本地函数定义是非法的是函数内部定义函数的错误,C,C++函数不可以在函数内部定义函数。2)与左侧的大括号"{"匹配之前遇到文件结束,和第一个问题是相关的,是这个问题导致的第一个问题的出现.PS:实际原因往往是...
  • 腾讯云的函数计算提供了很多运行库,对.NET的支持需要通过custom runtime 来支持,可以支持任何版本的.NET Core,也就是需要自定义runtime,需要使用到函数计算的custom runtime功能,具体参见https://clo...
  • 本文将为大家介绍使用函数计算部署深度学习 AI 推理的最佳实践, 其中包括使用 FUN 工具一键部署安装第三方依赖、一键部署、本地调试以及压测评估, 全方位展现函数计算的开发敏捷特性、自动弹性伸缩能力、免运维和...
  • 我们看到分母一个二次函数联想到定义域,我们自然就想到了:判别式肯定要小于0的:而我们根据题目给出的条件,可以知道:这说明了什么呢?这说明,分母不可能无解,所以要使得定义域为实数,那么只能有一种可能...
  • 功能介绍今天在函数计算上实现一个Web站点比较简单的,比如: 部署基于 python wsgi web 框架的工程到函数计算 介绍的用WSGI框架结合函数计算部署Python的Web App。最近函数计算发布了一个新功能,使得搬站进一步...
  • 上一节较为详细的讨论了C++语言中基类被派生类继承过程中的内存模型,尤其较为详细的分析了虚函数及其虚表、虚表指针在内存中如何分布,如何存储的,这对于理解C++语言中的“动态绑定”极有帮助的。对于理解C++...
  • 使用C++开发过程序时,定义函数可以指定...这一个很好用的特性,那么在C语言程序开发中,是否也可以定义带“默认参数”的函数呢?C语言程序开发中,是否也可以定义带“默认参数”的函数呢有“默认参数”的C语言函...
  • 文章目录@[toc]现象原因解决方法 现象 从代码服务器clone同事代码,构建时报错如下: 原因 习惯原因,使用了Windows Terminal clone 了代码。 git 为了兼容跨系统间不同行尾符的问题,进行了行尾符的转换处理,细节...
  • 目录:trick:Hands-On Design Patterns With C++(零)前言​zhuanlan.zhihu.com本地缓存优化(上)trick:Hands-On Design Patterns With C++(十)本地缓存优化(上)​zhuanlan.zhihu.com本地缓存优化(下)本地...
  • #include "stdafx.h" #include "stdafx.h" #include<iostream>...这个程序运行后总会出现[color=#FF00FF]“main”: 本地函数定义是非法的[/color],请大虾们帮帮我,毕业论文急需要的,万分感激!!!
  • #include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { static int j; //void fun1(void) void fun1() { static int i = 0;...}
  • // TestGULT.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <GL/glut.h> #include <math.h> void myinit(void) { glClearColor(1.0, 1.0, 1.0, 0.0); //置背景色 ...
  • 检查前一个接口的大括号是否匹配正确。 一个一个的找匹配。
  • 不能在成员函数xxx的类外部重新声明该函数

    万次阅读 多人点赞 2015-04-13 14:38:52
    错误 2 error C2601: “CHIKIPCamera::SetPtzParam”: 本地函数定义是非法的 d:\work\project\mediaclient\code\mediaclient\ctsrtsp\hikipcamera.cpp 98 1 CTSRtsp 错误 3 error C2601: “CHIKIPCamera::...
  • “{”: 未找到匹配令牌

    千次阅读 2020-05-19 09:59:04
    解决方法: 1、查询{}两个符号是否匹配; 2、因为Windows和Unix不同的标准,(从别人那拷过来的代码); 1)找到确切的地址然后自己手打两个;...tips:本地函数定义是非法的;这个问题也可能是这个原因 ...
  • “{”: 未找到匹配令牌(脑残操作)

    千次阅读 2019-10-31 20:29:06
    问题:如题 解决方法: 1、查询{}两个符号是否匹配; 2、因为Windows和Unix不同的标准,(从别人那拷过来的代码); ①找到确切的地址然后自己手打两个;...tips:本地函数定义是非法的;这个问题也可能是这个原因 ...
  • bug汇总

    2012-04-04 14:51:32
    1.C2601:MSDN上关于C2601的帮助:“function”: 本地函数定义是非法的代码试图在函数内定义函数。或者,在该 C2601 错误位置前的源代码中有一个额外的大括号。 2.fatal error LNK1168: cannot open Debug/SHI.exe ...
  • 比如下面这个问题 long double ld=3....为什么会提示 “a”本地函数定义是非法的,而c,d却又没问题呢?这跟a用花括号定义有什么联系? ()是调用了类型的构造函数初始化,对于内置类型来说,编译器有默认...
  • local function definitions are illegal

    千次阅读 2010-06-21 10:06:00
     今天程序碰到了这样一个错误,local function definitions are illegal,本地函数定义是非法的。  错误原因:(1)这一系列报错前的那个函数中少了一个“}”。  (2)函数里面不能定义函数....
  • 1、一般都是非法内存操作,例如数组越界,例如申请a[5],却访问到a[5]或者a[6],这也会有很多情况,可能是循环操作时循环变量控制有问题,可能是字符串拷贝时长度发生溢出; 2、指针指向了非法内存,例如定义了一个指针,...
  • 小妙招

    2016-12-03 19:25:43
    刚刚犯了一个错误,头文件中有一个函数少了一个括号(报的错本地函数定义非法”),却在cpp里面报错,查了很久没查出来,看了百度,总结有以下方法:  1、注释逐步排除确定那一块错了  2、在那一块中用...
  • 等)定义一套钩子函数(hook),其中IPv4 定义了5 个钩子函数.内核的模块可以对每种协议注册多个钩 子,这样当某个数据包通过Netfilter 框架时,Netfilter 检测是否有任何模块对该协议和钩子函数进行了 注册.若有,则将该...

空空如也

空空如也

1 2 3 4
收藏数 68
精华内容 27
关键字:

本地函数定义是非法的