天道酬勤,学无止境

Get type completion based on dynamic (mapped/conditional) type

You can drop the following code into a foo.ts file. I am trying to dynamically generate types. What I am doing is based off this question: Map array to an interface

type TypeMapping = {
  Boolean: boolean,
  String: string,
  Number: number,
  ArrayOfString: Array<string>,
}

export enum Type {
  Boolean = 'Boolean',
  String = 'String',
  Number = 'Number',
  ArrayOfString = 'ArrayOfString'
}

const asOptions = <K extends Array<string>, T extends Array<{ name: K, type: keyof TypeMapping }>>(t: T) => t;

type OptionsToType<T extends Array<{ name: Array<string>, type: keyof TypeMapping }>>
  = { [K in T[number]['name'][0]]: TypeMapping[Extract<T[number], { name: K }>['type']] }


const options = asOptions([
  {
    name: ['foo'],
    type: Type.Boolean
  },

  {
    name: ['bar'],
    type: Type.String
  },

  {
    name: ['baz'],
    type: Type.Number
  },

  {
    name: ['bab'],
    type: Type.ArrayOfString
  }
]);



export type Opts = OptionsToType<typeof options>;

const v = <Opts>{foo: true};  // this does not compile

console.log(typeof v.foo);

I don't get any type completion - when I type v. nothing shows up.

评论

Here is an example that uses Typescript 3, and an object as the input. I do something very similar to this in my own projects to generate a typed query builder wrapper for knex.js from my Postgres database.

// for lazier enum/mapping declaration
function StrEnum<T extends string[]>(...values: T) {
  let o = {};
  for (let v in values) {
    o[v] = v;
  }
  return o as { [K in T[number]]: K };
}
// declare enum values
const Type = StrEnum("Boolean", "String", "Number", "ArrayOfString");

// correlate the keys to things
type TypeMapping = {
  Boolean: boolean;
  String: string;
  Number: number;
  ArrayOfString: Array<string>;
};

// thing to convert your generated interface into something useful
const asOptions = <T extends { [key: string]: keyof TypeMapping }>(t: T) => t;

// the generated object
const options = asOptions({
  foo: Type.Boolean,
  bar: Type.String,
  baz: Type.Number,
  bab: Type.ArrayOfString
});

type Opts = Partial<
  { [V in keyof typeof options]: TypeMapping[typeof options[V]] }
>;

const v: Opts = { foo: true }; // this does compile

console.log(v);

Here is a way to use your current interface:

// for lazier enum/mapping declaration
function StrEnum<T extends string[]>(...values: T) {
  let o = {};
  for (let v in values) {
    o[v] = v;
  }
  return o as { [K in T[number]]: K };
}
// declare enum values
const Type = StrEnum("Boolean", "String", "Number", "ArrayOfString");

// correlate the keys to things
type TypeMapping = {
  Boolean: boolean;
  String: string;
  Number: number;
  ArrayOfString: Array<string>;
};

type OptDefinitionElement<K extends string, V extends keyof TypeMapping> = {
  name: K;
  value: V;
};

// thing to convert your generated interface into something useful
const asOptions = <T extends OptDefinitionElement<any, any>[]>(...t: T) => {
  return t;
};

// because typescript doesn't like to infer strings
// nested inside objects/arrays so precisely
function InferString<S extends string>(s: S) {
  return s;
}

// the generated object
const options = asOptions(
  { name: InferString("foo"), value: Type.Boolean },
  { name: InferString("bar"), value: Type.String },
  { name: InferString("baz"), value: Type.Number },
  { name: "bab" as "bab", value: Type.ArrayOfString } // note you don't *have* to use the Infer helper
);

// way to iterate keys and construct objects, and then result in the | type of all
// of the values
type Values<T extends { [ignoreme: string]: any }> = T extends {
  [ignoreme: string]: infer R;
}
  ? R
  : never;
type OptionsType = typeof options;
type OptionKeys = Exclude<keyof OptionsType, keyof Array<any>>;
type Opts = Values<
  {
    [TupleIndex in Exclude<keyof OptionsType, keyof Array<any>>]: {
      [key in OptionsType[TupleIndex]["name"]]: TypeMapping[OptionsType[TupleIndex]["value"]]
    }
  }
>;

const v: Opts = { foo: true }; // this does compile

console.log(v);

Assuming you are using the first element of the name property as the actual key to add to the resultant type, your definitions are a little off. I would fix them to be:

const asOptions = <
  K extends string, 
  T extends Array<{ name: {0: K}, type: keyof TypeMapping }>
>(t: T) => t;

type OptionsToType<T extends Array<{ name: Array<string>, type: keyof TypeMapping }>> = {
  [K in T[number]['name'][0]]: TypeMapping[Extract<T[number], { name: {0: K} }>['type']] 
}

The differences:

  • I am still using K extends string to induce inference of a string literal in asOptions. There are places where TypeScript infers string literals and other places where it infers just string, and K extends Array<string> will not infer a string literal. So K is still a string type, and instead I've made the name property as {0: K} which will ensure that it inspects the first element of the array.

  • Again in OptionsToType, K is a string literal, so you must extract the piece of T['number'] that has K as the first element of the name property, which is Extract<T[number], {name: {0: K} }>.

The rest should work now, I think. Hope that helps. Good luck.

受限制的 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>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • C++类型转换
    显示转换 C ++是一种强类型的语言。许多转换,特别是那些暗示对值的不同解释的转换,都需要显式转换,在C ++中称为类型转换。通用类型转换存在两种主要语法:函数形式和像c一样的形式: double x = 10.3; int y; y = int (x); // 函数形式 y = (int) x; // 像c一样的形式 这些通用类型转换的功能,可以满足基本数据类型的大多数需求。但是,这些运算符也可以应用于类和指向类的指针,这可能会产生代码,在语法上正确;但同时会导致运行时错误。例如,下面的代码编译没有错误: 例子 #include <iostream> using namespace std; class product { string name; }; class employee { string name; int age; public: employee (string emp_name, int emp_age) { name = emp_name; age= emp_age; } int get_age() { return age; } }; int main () { product d; employee * padd; padd = (employee *) &d; cout << padd->get_age(); return 0; }
  • 来自“ void *”的dynamic_cast(dynamic_cast from “void *”)
    问题 据此, void*没有RTTI信息,因此从void*强制转换是不合法的,而且很有意义。 如果我没记错的话,来自void* dynamic_cast正在gcc上工作。 您能澄清一下这个问题吗? 回答1 dynamic_cast仅适用于多态类型,即包含虚函数的类。 在gcc中,您可以dynamic_cast到void*但不能从: struct S { virtual ~S() {} }; int main() { S* p = new S(); void* v = dynamic_cast<void*>(p); S* p1 = dynamic_cast<S*>(v); // gives an error } 回答2 在5.2.7 - Dynamic cast [expr.dynamic.cast]它表示对dynamic_cast<T>(v) : 如果T是指针类型,则v将是指向完整类类型的指针的右值如果T是引用类型,则v应该是完整类类型的左值(感谢usta对我遗漏的内容进行评论) ... 否则, v将是多态类型的指针或左值 因此,否,不允许使用(void*)值。 让我们考虑一下您的请求可能意味着什么:说您有一个真正指向Derived1*的指针,但是代码dynamic_cast -ing只知道它是一个void* 。 假设您正在尝试将其转换为Derived2*
  • 为什么要呼叫ISet .Contains()编译,但是在运行时引发异常?(Why calling ISet<dynamic>.Contains() compiles, but throws an exception at runtime?)
    问题 请帮我解释以下行为: dynamic d = 1; ISet<dynamic> s = new HashSet<dynamic>(); s.Contains(d); 代码编译时没有错误/警告,但是在最后一行,我得到以下异常: Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.Generic.ISet<object>' does not contain a definition for 'Contains' at CallSite.Target(Closure , CallSite , ISet`1 , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1) at FormulaToSimulation.Program.Main(String[] args) in 据我所知,这与动态重载解析有关,但是奇怪的是 (1)如果s的类型为HashSet<dynamic> ,则不会发生异常。 (2)如果我将非通用接口与接受动态参数的方法一起使用,则不会发生异常。 因此
  • 虚函数和多重继承的情况下的对象布局(Object layout in case of virtual functions and multiple inheritance)
    问题 最近有人在采访中问我有关具有虚拟功能和涉及多重继承的对象布局的问题。 我在没有多继承的情况下如何实现它(即编译器如何生成虚拟表,在每个对象中插入指向虚拟表的秘密指针等等)的上下文中对此进行了解释。 在我看来,我的解释中缺少一些东西。 所以这是问题(请参见下面的示例) C类对象的确切内存布局是什么? C类的虚拟表条目。 A,B和C类的对象的大小(由sizeof返回)。(8,8,16 ??) 如果使用虚拟继承该怎么办。 当然应该影响大小和虚拟表条目吗? 示例代码: class A { public: virtual int funA(); private: int a; }; class B { public: virtual int funB(); private: int b; }; class C : public A, public B { private: int c; }; 谢谢! 回答1 内存布局和vtable布局取决于您的编译器。 以我的gcc为例,它们看起来像这样: sizeof(int) == 4 sizeof(A) == 8 sizeof(B) == 8 sizeof(C) == 20 注意,每个编译器和平台之间,sizeof(int)和vtable指针所需的空间也可能有所不同。 sizeof(C)== 20而不是16的原因是gcc为A子对象提供了8个字节
  • C++ 四种类型转换操作符
    在c++中进行类型转换只需要在变量前加上变量类型,并且转换是双向的。 例如: int i = 0; double d = 1.9; int i1 = (int) d; double d1 = (double) i; 这种类型转换方式只适用于基本数据类型,对复杂的自定义类型不适用。 因此,C++中提供了四种类型转换符:static_cast、dynamic_cast、const_cast、reinterpret_cast。 1、dynamic_cast dynamic_cast用于类继承层次间的指针或引用转换。主要还是用于执行“安全的向下转型(safe downcasting)”,也即是基类对象的指针或引用转换为同一继承层次的其他指针或引用。至于“向上转型”(即派生类指针或引用类型转换为其基类类型),本身就是安全的,尽管可以使用dynamic_cast进行转换,但这是没必要的, 普通的转换已经可以达到目的,毕竟使用dynamic_cast是需要开销的。 不同于其它的强制类型转换,dynamic_cast在运行时会进行类型检查,如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast失败: class Base(){virtual void dummy(){} }; class Derived:public Base{}; Base *b1 = new Base
  • 虚拟赋值运算符C ++(virtual assignment operator C++)
    问题 可以将C ++中的Assignment Operator虚拟化。 为什么需要它? 我们也可以使其他运营商虚拟吗? 回答1 不需要将赋值运算符设为虚拟。 下面的讨论是关于operator= ,但它也适用于接受了该类型的任何运算符重载,以及接受了该类型的任何函数。 下面的讨论表明,在寻找匹配函数签名方面,虚拟关键字不知道参数的继承。 在最后一个示例中,它显示了在处理继承类型时如何正确处理分配。 虚函数不知道参数的继承: 函数的签名必须相同,虚拟函数才能发挥作用。 因此,即使在以下示例中,将operator =设为虚拟,该调用也永远不会充当D中的虚拟函数,因为operator =的参数和返回值不同。 函数B::operator=(const B& right)和D::operator=(const D& right) 100%完全不同,被视为2个不同的函数。 class B { public: virtual B& operator=(const B& right) { x = right.x; return *this; } int x; }; class D : public B { public: virtual D& operator=(const D& right) { x = right.x; y = right.y; return *this; } int y; }
  • 多重继承:从void *转换为第二基类后出现意外结果(multiple inheritance: unexpected result after cast from void * to 2nd base class)
    问题 我的程序需要使用void *才能在动态调用情况下传输数据或对象,以便它可以引用任意类型的数据,甚至是原始类型的数据。 但是,我最近发现,在具有多个基类的类的情况下,将这些void *向下转换的过程失败,甚至在调用这些向下转换的指针上的方法后,即使内存地址似乎正确,我的程序也崩溃了。 崩溃发生在访问“ vtable”的过程中。 所以我创建了一个小测试用例,环境是Mac OS X上的gcc 4.2: class Shape { public: virtual int w() = 0; virtual int h() = 0; }; class Square : public Shape { public: int l; int w() {return l;} int h() {return l;} }; class Decorated { public: int padding; int w() {return 2*padding;} int h() {return 2*padding;} }; class DecoratedSquare : public Square, public Decorated { public: int w() {return Square::w() + Decorated::w();} int h() {return Square::h() +
  • 来自 void 的 Cast 的运行时检查*(Run-Time Checking of a Cast from a void*)
    问题 假设我有一个void*包含一个指向未知class的指针。 我想使用dynamic_cast对我实际拥有的类的类型进行运行时检查。 例如: class Foo {}; void* bar = new Foo; 如果我尝试执行dynamic_cast<Foo*>(bar)我得到: “void *”:dynamic_cast 的表达式类型无效 但是我需要dynamic_cast因为在我的实际情况下我不确定bar实际上是Foo* 。 我在这里读到,对此的一种解决方案是为bar可能包含的所有对象创建一个基类, reinterpret_cast指向该基类的指针,然后尝试从该对象指针进行dynamic_cast到Foo 。 这对我来说很困难,因为bar中可能存储的对象并不都在我的控制之下。 (并且因为尝试重新创建 Java 让我感到胃灼热。)还有其他方法可以做到这一点吗? 回答1 dynamic_cast用于将多态对象转换为一个类,该类具有您尝试转换为父对象的对象的类型。 void*与此完全不同。 使用指向 void 的指针,您实际上是在剥离所有类型信息。 dynamic_cast知道有一个基类并且可以通过 RTTI 进行类型检查。 当你抛出一个空指针时,你对编译器说:“是的,你知道内存中的这个地方?好吧,将它用作这种类型”,如果内存无效,则调用 UB。 你在这里有三个选择。 选项
  • 【深入理解JVM】学习笔记——-8、虚拟机字节码执行引擎
    八、虚拟机字节码执行引擎 你只管努力, ——剩下的交给时光。 老规矩,先上图,大致了解一下: 一. 概述 执行引擎是 Java 虚拟机最核心的组成部分之一。“虚拟机” 是一个相对于 “物理机” 的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、硬件、指令集和操作系统层面上的,而虚拟机的执行引擎则是由自己实现的,因此可以自行制定指令集与执行引擎的结构体系,并且能够执行哪些不被硬件直接支持的指令集格式。 在 Java 虚拟机规范中制定了虚拟机字节码执行引擎的概念模型,这个概念模型称为各种虚拟机执行引擎的统一外观(Facade)。在不同的虚拟机实现里面,执行引擎在执行 Java 代码的时候可能会有解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)两种选择,也可能两者兼备,甚至还可能会包含几个不同级别的编译器执行引擎。但从外观上看起来,所有的 Java 虚拟机的执行引擎都是一致的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。 二. 运行时栈帧 栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用开始至执行完成的过程
  • C# DLR,使用 Dynamic 关键字进行数据类型推断(C# DLR, Datatype inference with Dynamic keyword)
    问题 只是问问 : 为什么 'withOffset' 变量被推断为动态,因为Parse 方法返回 Struct ? dynamic str = "22/11/2013 10:31:45 +00:01"; var withOffset = DateTimeOffset.Parse(str); 在显式转换回 Struct 之后? dynamic str = "22/11/2013 10:31:45 +00:01"; var withOffset = DateTimeOffset.Parse((string)str); 因为 DateTimeOffset.Parse 的返回类型是 DateTimeOffset,编译器必须知道这一点。 记住这一点,无论它在运行时调用什么方法,返回值始终是 DateTimeOffset。 规格说明 由于您的方法将 dynamic 作为参数,因此它符合“动态绑定”的条件 有点腥。 有这样的规范有什么意义? 或者在哪种情况下 DateTimeOffset.Parse 不会返回 STRUCT(暂时忘记 DLR ..)? 编译器需要很聪明,如果类中的所有方法/重载都具有相同的返回类型以从长远来看获得性能优势。 回答1 当您使用dynamic ,整个表达式在编译时被视为动态表达式,这会导致编译器将所有内容都视为动态并获得运行时绑定。 这在 C# 语言规范的 7.2
  • 四种强制类型转换
    四种强制类型转换 c++动态类型转换有四种const_cast、static_cast、dynamic_cast、reinterpreter_cast。 这四种动态类型转换的方法其实都很接近: cast-name <typename> (expression) 其中cast-name为static_cast、dynamic_cast、const_cast 和 reinterpret_cast之一,typename为需要转换的目标类型,而expression是被强制转换的值。 1、 static_cast(静态转换) 它可以完成以下类型转换: 1、父类到子类的转换,( 进行下行转换,把基类的指针或引用转换为派生类表示)不保证安全。 2、子类到父类的转换,(进行上行转换,把派生类的指针或引用转换成基类表示)保证安全。 3、基本数据类型之间的转换,是否正确需要开发人员来保证。 4、void 类型的空指针,转换成其他类型空指针。 5、可以把任何类型的表达式 转换为 void类型。 static_cast不能转换掉表达式的const、volitale属性。 2、 dynamic_cast(动态转换) dynamic 支持运行指针时,识别指针类型或所引用的对象。 换句话说,它可以在执行期决定真正的类型,如果基类指针真的指向了子类对象,它便返回指子类对象的指针值,否则,则返回空指针。(所以说到底
  • 常规转换 vs. static_cast vs. dynamic_cast [重复](Regular cast vs. static_cast vs. dynamic_cast [duplicate])
    问题 这个问题已经在这里有了答案: 什么时候应该使用 static_cast、dynamic_cast、const_cast 和 reinterpret_cast? (9 个回答) 6年前关闭。 我已经编写 C 和 C++ 代码将近 20 年了,但是我从未真正理解这些语言的一个方面。 我显然使用过常规演员表,即 MyClass *m = (MyClass *)ptr; 各地,但似乎还有其他两种类型的演员,我不知道两者之间的区别。 以下代码行之间有什么区别? MyClass *m = (MyClass *)ptr; MyClass *m = static_cast<MyClass *>(ptr); MyClass *m = dynamic_cast<MyClass *>(ptr); 回答1 static_cast static_cast用于您基本上想要反转隐式转换的情况,但有一些限制和添加。 static_cast执行运行时检查。 如果您知道您引用了特定类型的对象,则应该使用它,因此无需检查。 例子: void func(void *data) { // Conversion from MyClass* -> void* is implicit MyClass *c = static_cast<MyClass*>(data); ... } int main() { MyClass c
  • C ++-在没有RTTI / dynamic_cast的情况下向下转换钻石形状继承的对象(C++ - downcasting a diamond shape inherited object without RTTI/dynamic_cast)
    问题 我目前正在整合在非RTTI平台(Android)上使用大量RTTI内容的第三方程序包。 基本上,我执行了自己的RTTI实现,但遇到了问题。 问题是很多类都具有钻石继承问题,因为所有类都派生自同一个基类(对象)。因此,如果我要将基类降级为派生类,则必须使用dynamic_cast-但RTTI不可用! 在没有dynamic_cast的虚拟继承的情况下,如何将对象从父对象转换为子对象? 看起来像这样: class A { public: virtual char* func() { return "A"; }; }; class B : public virtual A { public: //virtual char* func() { return "B"; }; }; class C : public virtual A { public: //virtual char* func() { return "C"; }; }; class D : public B, public C { public: //virtual char* func() { return "D"; }; }; D d; A* pa = static_cast<A*>(&d); D* pd = static_cast<D*>(pa); // can't do that! dynamic_cast
  • 什么时候可以安全地在构造函数和析构函数中调用this->(When is it safe to call this-> in constructor and destructor)
    问题 到目前为止,我还没有找到最终的答案。 什么时候从对象内部调用this->是安全的。 尤其是从构造函数和析构函数内部。 而且,在使用公共继承时。 在此调用的结果上使用上下转换是否安全? 因此,例如: class foo { foo(): a(), b(this->a)//case 1 { this-> a = 5; //case 2 } int a; int b; }; class bar: public baz { bar(): baz(this)//case 3 - assuming baz has a valid constructor { } } 最后是最不可能的一个 foo() { if(static_cast<bar*>(this));//case 4 } 以上哪种情况是合法的? 注意:我知道上述许多做法都不可取。 回答1 在任何非静态成员函数中, this指向调用该函数的对象。 只要是有效的对象,就可以安全使用。 在构造函数或析构函数的主体内,存在当前正在构造的类的有效对象。 但是,如果这是某个派生类的基础子对象,则此时只有基础子对象有效;否则,该基础子对象才是有效的。 因此,向下转换并尝试访问派生类的成员通常是不安全的。 出于同样的原因,您在这里需要小心地调用虚函数,因为虚函数是根据正在创建或销毁的类而不是最终的替代程序来分派的。 在构造函数的初始化程序列表中
  • C#4.0“动态”和foreach语句(C# 4.0 'dynamic' and foreach statement)
    问题 在不久之前,我发现新的dynamic关键字无法与C#的foreach语句配合使用: using System; sealed class Foo { public struct FooEnumerator { int value; public bool MoveNext() { return true; } public int Current { get { return value++; } } } public FooEnumerator GetEnumerator() { return new FooEnumerator(); } static void Main() { foreach (int x in new Foo()) { Console.WriteLine(x); if (x >= 100) break; } foreach (int x in (dynamic)new Foo()) { // :) Console.WriteLine(x); if (x >= 100) break; } } } 我期望对dynamic变量进行迭代应该完全起作用,就好像在编译时知道集合变量的类型一样。 我发现编译时第二个循环实际上看起来像这样: foreach (object x in (IEnumerable) /* dynamic cast */ (object)
  • C++中的多态类型是什么?(what's polymorphic type in C++?)
    问题 我在一篇文章中发现“static_cast 用于非多态类型转换,而 dynamic_cast 用于多态类型转换”。 我知道 int 和 double 不是多态类型。 但是,我还发现可以在基类和派生类之间使用 static_cast。 这里的多态类型是什么意思? 有人说多态类型是指带有虚函数的基类。 是对的吗? 这是唯一的情况吗? 还有什么? 有人可以为我详细说明一下吗? 回答1 首先,这篇文章并不完全正确。 dynamic_cast检查对象的类型并且可能会失败, static_cast不检查并且在很大程度上需要程序员知道他们在做什么(尽管它会为一些严重的错误发出编译错误),但它们可能都用于多态情况。 ( dynamic_cast有一个附加要求,即至少涉及的类型之一具有虚拟方法。) 简而言之,C++ 中的多态性是通过单独定义的接口使用对象。 该接口是基类,并且几乎总是只有在它具有虚拟方法时才有用。 然而,在没有任何虚方法的情况下具有多态性是罕见但可能的。 通常,这表明设计不佳或必须满足外部要求,因此,无法举出适合此处的好示例。 (不幸的是,“当您看到它时,您就会知道何时使用它”,这是我在这里可以给您的最佳建议。) 多态示例: struct Animal { virtual ~Animal() {} virtual void speak() = 0; }; struct Cat
  • 通过基类虚函数获取派生类型(Get derived type via base class virtual function)
    问题 我正在尝试通过基类虚函数获取对象的派生类型。 我已经写了这个,它不能编译: struct base { virtual base& get_this() { return *this; } }; struct derived : base { virtual derived& get_this() override { return *this; } void fn(); }; int main () { base* pd = new derived(); derived& x = pd->get_this(); /*ERROR*/ x.fn(); return 0; } ……给我一个错误:我无法从base初始化derived& 。 由于get_this是虚拟的,为什么pd->get_this()返回一个base&而不是derived& ? 提前致谢! 编辑: 感谢大家的有用回答和对我的延迟回复表示歉意。 我应该在原始帖子中指定我也对解决我的问题感兴趣,而不是仅仅弄清楚为什么上面的内容不能编译。 我的主要问题是fn对于derived类是唯一的,无法通过基类调用。 使用强制转换肯定可以解决问题,但是我讨厌用if else构造代码来获取正确的类型(Scott Meyers也建议不要强制转换:))。 答案似乎表明,转型是必须走的路,这至少在某种程度上使我放心,我不会忽略对问题的更
  • 高灵活度,高适用性,高性能,轻量级的 ORM 实现
    我需要的不是一个与数据库表映射的ORM,而是需要一个与内存数据集动态映射的ORM。ORM(Object-Relational Mapping 对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,目的是提供易于理解的模型化数据的方法。 ORM虽然有诸多好处,但是在实际工作中,容易发现在大型项目开发中,ORM存在一些缺点,在复杂场景下,反而容易大大增加开发的复杂度及牺牲灵活度。使用ORM不写SQL而使数据库交互变得简单易行,是否能够达到预期效果,要画一个问号。主要问题可能存在于以下几点:1.牺牲一定的性能。2.虽然隐藏了数据层面的设计,但并没有从根本上降低数据访问复杂度,只是将复杂纬度从一个点(SQL,存储过程)转移到另一个点(代码)。3.对于复杂查询,ORM力不从心,虽然从技术角度说实现肯定都能实现,但是代价是不值的。 此外,最重要的一点,对于大型项目的开发,表示数据的实体类和数据库层面的持久化设计并非一一对应的关系,使用ORM根据数据库表生成一一对应的实体类模型,并不能完全适用。同时,在实体类中,需要进行其它编码工作,如额外的属性定义,附加额外的Attribute,部分功能实现和业务操作等,而使用ORM来生成实体类,生成时会覆盖现有实体类而导致项目自身的编码工作丢失。 我希望的ORM框架能够有以下几个特点(设计目标)1.支持所有数据库原生操作
  • 向下转换shared_ptr 到shared_ptr ?(Downcasting shared_ptr<Base> to shared_ptr<Derived>?)
    问题 我正在尝试初始化指向派生类的共享指针,而又不丢失引用计数: struct Base { }; struct Derived : public Base { }; shared_ptr<Base> base(new Base()); shared_ptr<Derived> derived; // error: invalid conversion from 'Base* const' to 'Derived*' derived = base; 到目前为止,一切都很好。 我没想到C ++会将Base *隐式转换为Derived *。 但是,我确实想要代码表示的功能(即在向下转换基本指针的同时保持引用计数)。 我的第一个想法是在Base中提供一个强制转换运算符,以便可以隐式转换为Derived(对于pedants:我会检查向下强制转换是否有效,不用担心): struct Base { operator Derived* (); } // ... Base::operator Derived* () { return down_cast<Derived*>(this); } 好吧,这没有帮助。 看来编译器完全忽略了我的类型转换运算符。 有什么想法可以使shared_ptr分配工作吗? 值得一提的是: Base* const类型是什么类型? const Base*我了解,但是Base*
  • Oceanus:美团点评HTTP流量定制化路由的实践
    总第278篇2018年 第70篇背景Oceanus是美团基础架构部研发的统一HTTP服务治理框架,基于Nginx和ngx_lua扩展,主要提供服务注册与发现、动态负载均衡、可视化管理、定制化路由、安全反扒、session ID复用、熔断降级、一键截流和性能统计等功能。本文主要讲述Oceanus如何通过策略抽象、查询、渲染和分组动态更新,实现HTTP请求的定制化路由。随着公司业务的高速发展,路由场景也越来越复杂。比如:由于公司早期的业务场景相对比较简单,所以均通过Nginx if指令支持。比如某业务要把来源IP为10.4.242.16的请求转发到后端节点10.4.232.110,其它请求转发到后端节点10.4.232.111和10.4.232.112,就可以进行如下配置:upstream backend_aaa { server 10.4.232.110:8080 weight=10;}upstream backend_bbb { server 10.4.232.111:8080 weight=10; server 10.4.232.112:8080 weight=10;}location /abc { if($remote_ip = "10.4.242.16") { proxy_pass http://backend_aaa; #路由到backend_aaa集群 } proxy