【问题标题】:How do programs know the types at runtimes of primitives statically typed languages程序如何知道原始静态类型语言在运行时的类型
【发布时间】:2016-07-18 14:05:17
【问题描述】:

Go 和 Scala 都提供了在运行时检查类型的方法:

斯卡拉:

class A
class B extends A

val a: A = new A // static type: A dynamic type: A
val ab: A = new B // static type: A dynamic type: B
val b: B = new B // static type: B dynamic type: B

def thing(x: Any): String = x match {
    case t: Int => "Int"
    case t: A => "A"
    case t: B => "B"
    case t: String => "String"
    case _ => "unknown type"
}

去:

package main

import (
    "fmt"
    "reflect"
)

struct A {
    field1 int
    field2 string
}

func printTypeOf(t interface{}) {
    fmt.Println(reflect.TypeOf(t))
}

func main() {
    i := 234234 // int
    s := "hello world" // string
    p := &A{3234234, "stuff"} // *A

    fmt.Print("The type of i is: ")
    printTypeOf(i)
    fmt.Print("The type of s is: ")
    printTypeOf(s)
    fmt.Print("The type of p is: ") // pass a pointer
    printTypeOf(p)
    fmt.Print("The type of the reference of p is: ") // pass a value
    printTypeOf(*p)
}

这在内部究竟是如何工作的?我假设对于结构和类,对象的类型存储在一个隐藏字段中(所以 golang 中的结构实际上是 struct { field1 int field2 string type type }。但是到底如何才能发挥作用,给出 11010110 并知道它是否是指向内存地址 214 的指针,整数 214 还是字符 Ö?是否所有的值都偷偷地用一个代表其类型的字节传递?

【问题讨论】:

  • 您的假设不正确,Go 结构中没有隐藏字段。所有类型在编译时对编译器都是已知的。
  • Go,简单来说:当你调用printTypeOf(x) 时,x 被包装在一个接口值中。该值具有您所考虑的“隐藏字段”。
  • 鉴于它是包装好的,这是有道理的

标签: scala reflection go types


【解决方案1】:

在 Scala 中,每个对象都有一个指向其类的指针。当您使用原始参数(IntChar 等)调用 thing 时,它会自动装箱到一个对象(java.lang.Integerjava.lang.Character 等)。代码中与Int 的匹配实际上被转换为与Integer 的匹配。

在 Go 中,类型不存储在结构中,而是存储在接口值中:

Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to the associated data. Assigning b to an interface value of type Stringer sets both words of the interface value.

因此,当您调用 printTypeOf(whatever) 时,whatever 将转换为 interface {},并且其类型与 whatever 本身一起存储在此新值中。

【讨论】:

  • 好的,我可以看到 Go 中的 interface{} 类型和 Scala 中的对象是如何工作的。只需使用正确的偏移量并获取类型信息。但是,如果我传递一个由字节 11010110 表示的普通旧整数,它怎么知道我的意思是整数,而不是指针或字符,并用指向整数类型的指针将其装箱。
  • 换句话说,Scala 是如何将 11010110 装箱到值字段为 214 的 Integer 类而不是值为 Ö 的 Character 类?
  • “但是如果我传递一个由字节 11010110 表示的普通旧整数,它怎么知道我的意思是整数”通过它的静态类型。如果是Int,它就被装箱到Integer,如果CharCharacter,等等。如果是Any,它已经被装箱了。
  • 啊,好吧,这是有道理的,因为在我的 scala 示例中,ab get 匹配的是静态类型而不是动态类型。但是静态类型不是只在编译时知道,而这些反射功能在运行时工作吗?
  • 不,它与运行时类型匹配。我的观点是,如果你有一个“普通旧整数”,它的静态(和运行时)类型是 always Int。所以编译器知道如何装箱。
猜你喜欢
  • 2011-02-09
  • 1970-01-01
  • 2010-10-07
  • 2011-10-29
  • 2016-09-26
  • 1970-01-01
  • 2011-02-11
相关资源
最近更新 更多