代码之家  ›  专栏  ›  技术社区  ›  sven

铸造和转化有什么区别[[副本]

  •  66
  • sven  · 技术社区  · 16 年前

    埃里克·利珀特的评论 this question

    13 回复  |  直到 9 年前
        1
  •  46
  •   Justin Niessner    16 年前

    铸造 是描述语法的术语(因此 句法 意思)。

    转换 语义的 意思)。

    显式表达式 类型。

    以及

    一种形式(T)E的铸造表达式, 一元表达式,执行显式 转换(§13.2)的值 键入T。

    似乎通过说语法中的cast操作符执行显式转换来支持这一点。

        2
  •  83
  •   chrissr    16 年前

    转换的意思是“我知道对象X不是类型Y,但是有一种方法可以从类型Y的X创建一个新对象,去做吧。”

        3
  •  42
  •   Eric Lippert    16 年前

    我想起理查德·费曼(Richard Feynman)讲的一个轶事,他正在上哲学课,教授问他:“费曼,你是物理学家,在你看来,电子是‘基本物体’吗?”于是费曼向全班提出了一个明确的问题:“砖头是基本物体吗?”。每个学生对那个问题都有不同的答案。他们说“砖块”的基本抽象概念是基本对象。不,一个特定的,独特的砖块是基本的对象。不,你能经验性地观察到的砖块部分是最基本的对象。等等。

    当然不是回答你的问题。

    我不会把这十几个答案通读一遍,和他们的作者辩论我真正的意思。我将在几周内写一篇关于这个问题的博客文章,我们将看看这是否对此事有帮助。

    打个比方吧,拉费曼。你想在星期六早上烤一条香蕉面包(我几乎每个星期六早上都会这么做),于是你就想到了烹饪的乐趣,上面写着“诸如此类。。。在另一个碗里,把干的配料搅拌在一起

    很明显,这一指示和你明天上午的行动之间有着密切的关系,但同样明显的是,将这些指示混为一谈是错误的 指令 . 说明书由正文组成。它在特定页面上有一个位置。它有标点符号。如果你在厨房里搅拌面粉和小苏打,有人问你“你现在的标点符号是什么?”你可能会觉得这是个奇怪的问题。动作与指令相关,但指令的文本属性不是动作的属性。

    铸造不是一种转化,就像食谱不是烘焙蛋糕一样。配方是描述一个动作的文本,然后你可以执行这个动作。cast操作符是描述运行时可以执行的操作(转换)的文本。

        4
  •  7
  •   Indeed is Trash    16 年前

    强制转换表达式用于转换 显式表达式
    ...
    一种形式(T)E的铸造表达式, 一元表达式,执行显式 转换(§13.2)的值

    因此,casting是一种语法结构,用于指示编译器调用显式转换。

    转换使表达式 将一种类型视为另一种类型 类型。转换可以是隐式的,也可以是 显式,这决定了 需要显式强制转换。 隐式,所以int类型的表达式 可以隐式地视为类型 很长。相反的转换,从 类型long到类型int,是显式的,所以 需要显式强制转换。

        5
  •  6
  •   Oded    16 年前

    只是我的理解,可能太简单了:

    转换时,将内部表示形式更改为其他形式-“我希望此int为字符串”。

        6
  •  5
  •   Paul Sasik    16 年前

    在读了埃里克的评论之后,用简单的英语尝试:

    铸造 意味着这两种类型在某种程度上是相同的。它们可以实现相同的接口或从相同的基类继承,或者目标可以“足够相同”(超集?),以便转换工作,例如从Int16转换到Int32。

    类型意味着这两个对象可能足够相似,可以进行转换。以数字的字符串表示为例。它是一个字符串,不能简单地转换成一个数字,需要对它进行解析并从一个转换成另一个,而且,这个过程可能会失败。它可能会失败,以及铸造,但我想这是一个更便宜的失败。

        7
  •  2
  •   Jeffrey L Whitledge    16 年前

    是从另一个类型的值创建一个类型的值。 转换 是一种类型的转换,其中值的内部表示也必须更改(而不仅仅是其解释)。

    在C#中,铸造和转换都是通过 :

    类型 一元表达式

    转换运算符声明符 . 因此,代码中只能创建(隐式或显式)转换。

    非转换隐式转换始终可用于子类型到父类型的转换,非转换显式转换始终可用于父类型到子类型的转换。不允许其他非转换强制转换。

        8
  •  1
  •   heisenberg    16 年前

        9
  •  0
  •   Dan Puzey    16 年前

    This page 在msdnc文档中,cast是转换的一个特定实例:“显式转换”,即形式的转换 x = (int)y 是演员阵容。

    myLong = myInt )是更通用的“转换”

        10
  •  0
  •   Toby    16 年前

    强制转换是类/结构上的运算符。转换是一个或另一个受影响的类/结构上的方法/进程,或者可能位于完全不同的类/结构中(即。 Converter.ToInt32()

    Cast操作符有两种类型:隐式和显式

    隐式cast运算符表示一种类型的数据(比如Int32)可以 总是 表示为另一种类型(十进制) .

    int i = 25;
    decimal d = i;
    

    总是 被忠实地表示为另一个类型(int),但可能会丢失数据/精度。因此编译器要求您 声明您知道这一点,并希望通过使用显式cast语法执行此操作:

    decimal d = 25.0001;
    int i = (int)d;
    

    转换采用两种不一定以任何方式相关的类型,并尝试通过某些过程(如解析)将一种类型转换为另一种类型。如果所有已知的转换算法都失败,则进程可能引发异常或返回默认值:

    string s = "200";
    int i = Converter.ToInt32(s); // set i to 200 by parsing s
    
    string s = "two hundred";
    int i = Converter.ToInt32(s); // sets i to 0 because the parse fails
    

        11
  •  0
  •   Community Mohan Dere    9 年前

    强制转换是句法的,可能涉及也可能不涉及转换(取决于强制转换的类型)。正如你所知道的,C++允许指定 the type of cast

    向上/向下转换层次结构可能被视为转换,也可能不被视为转换,这取决于您询问的对象 (他们在说什么语言!)

    Eric(C#)说,强制转换到不同的类型总是涉及转换,尽管转换甚至可能不会改变实例的内部表示。

    一个C++的家伙会不同意,因为 static_cast 可能不会产生任何额外的代码(因此“转换”实际上不是真实的!)

        12
  •  0
  •   maxwellb    16 年前

    Object.ToString() . 铸造仅由铸造操作员完成 (T) E ,这在其他文章中有描述,并且可以使用转换或装箱。

    它使用哪种转换方法?编译器根据编译时提供给编译器的类和库来决定。如果存在隐式转换,则不需要使用强制转换运算符。 Object o = String.Empty . 如果只存在显式转换,则必须使用casting运算符。 String s = (String) o .

    create explicit implicit 在您自己的类中使用转换运算符。注意:转换可以使数据看起来非常相似或与原始类型完全不同,但它都是由转换方法定义的,并且对编译器来说是合法的。

    总是

    Object o = float.NaN;
    String s = (String) o;
    

    但如果你进入 s ,例如 Console.WriteLine InvalidCastException . 因此,cast操作符仍然尝试在访问时使用转换,但在赋值期间将满足于装箱。

        13
  •  -6
  •   Community Mohan Dere    9 年前

    铸造和转化是一样的吗? 对“不”的回答以压倒性优势获得了赞成票 . 然而,我在这里的回答指出了为什么施法和转化不一样的生成本质,却被压倒性地否决了( 但是我在评论中有一个+1 ). 我想读者很难理解强制转换应用于表示语法/语义层,转换应用于操作语义层。例如,引用一个引用(或C/C++)的指针(引用一个盒式数据类型到另一个数据类型),并不会(在所有语言和场景中)生成盒装数据的转换。例如,在C中 float a[1]; int* p = (int*)&a; 不能保证 *p int 数据。

    编译器从 denotational operational semantics . 编译不是双射的,也就是说,不能保证将编译(如Java、LLVM、asm.js或C#字节码)反编译回编译成该字节码的任何表示语法(如Scala、Python、C#、C via Emscripten等)。因此这两层是不一样的。

    因此最明显的是 铸造 '和' 转换 “不是一回事。我的回答是,这些术语适用于两个不同的语义层。强制转换适用于表示层(编译器的输入语法)所知道的语义。转换适用于操作层(运行时或中间字节码)所知道的语义。我使用标准术语“erased”来描述没有显式记录在操作语义层中的指称语义发生了什么。

    拜托,伙计们,别再轻视一个比你知道得多的人了。投票前先做作业。


    INSERTED EDIT:Casting是发生在指称语义层(类型以其完整语义表示)的操作。强制转换可能(例如显式转换)也可能(例如向上转换)导致运行时语义层的转换。对我的回答投反对票(对马克·加文的评论投赞成票)向我表明,大多数人不理解两者之间的区别 denotational semantics and operational (execution) semantics


    我将更简单更全面地阐述埃里克·利珀特对所有语言的回答, 包括C# .

    铸造 语法是这样(像所有语法一样)的吗 转换 引起一些


    对于我所知的整个宇宙中的每一种计算机语言来说,这都是一个真实的说法。请注意,上述声明并没有这样说 铸造 转换 相互排斥。

    A 铸造 可能导致 转换 在运行时,但在某些情况下它可能不是。

    我们之所以有两个不同的词,即。 铸造 转换 语法 (演员)和 运行时

    保持概念的分离是很重要的,因为在某些编程语言中,强制转换从不引起转换。同时,我们也了解隐式铸造(例如。 upcasting

    我还想帮助读者了解我是如何在头脑中概括概念的,这对我作为计算机语言设计师很有帮助。我试图传递一种非常简约、抽象的思维方式。但我也试图用一种非常实际的方式来解释这一点。如果我需要改进说明,请随时在评论中告诉我。


    浇铸并不是一种转化,正如配方不是唯一的一样 烤蛋糕的动作。配方是描述动作的文本, 然后你就可以表演了。cast操作符是描述 操作—运行时可以执行的转换。

    配方就是语法中正在发生的事情。语法总是被删除,并替换为nothing或一些运行时代码。

    例如,我可以用C语言编写一个cast,它什么也不做,在编译时完全被删除 does not cause a change in the storage requirements 或者是 向上投射

    int x = 1;
    int y = (int)x;
    Giraffe g = new Giraffe();
    Animal a = (Animal)g;
    

    它可以用于文档目的(但有噪声),但在具有类型推断的语言中是必不可少的,在这种语言中,有时需要强制转换来告诉编译器您希望它推断什么类型。

    an example ,在斯卡拉 None Option[Nothing] 哪里 Nothing 是底部类型,即 附属的 超级的 -类型)。因此,有时使用None时,需要将类型强制转换为特定类型,因为 Scala only does local type inference ,因此不能总是推断出您想要的类型。

    // (None : Option[Int]) casts None to Option[Int]
    println(Some(7) <*> ((None : Option[Int]) <*> (Some(9) > add)))
    

    int x = (int)1.5 ,或者可能需要在运行时进行类型检查和可能的类型转换,例如。 downcasting . 强制转换(即语法)被删除并替换为运行时操作。

    因此,我们可以清楚地看到,将所有类型转换等同于显式转换,是一种隐含错误 MSDN documentation 操作人员


    添加 删除 .

    术语“erased”用于描述编译时已知的信息,而运行时不知道这些信息。例如,可以在非具体化泛型中删除类型,并将其称为 type erasure .

    一般来说,所有的语法都会被删除,因为CLI通常不是C#的双射(可逆的,一对一的)。您不能总是从一些任意的CLI代码返回到精确的C源代码。这意味着信息已被删除。

    那些说 删除 语法 ,它是指代语义(至少在向上和向下转换的情况下),表示在语义级别上我们要转换类型。现在,如何在运行时完成这一点是完全不同的语义级别。在某些语言中,它可能总是 NOOP . 例如,在Haskell中,所有类型信息都在编译时被删除。